From: <sag...@us...> - 2013-02-03 20:58:32
|
Revision: 1513 http://sourceforge.net/p/modplug/code/1513 Author: saga-games Date: 2013-02-03 20:58:24 +0000 (Sun, 03 Feb 2013) Log Message: ----------- [Fix] FT2 compatibility: Reverted envelope handling to pre-1.20 behaviour to fix EnvOff.xm (modelld after gh-kott.xm, where I noticed that the old behaviour was correct). EnvLoops.xm is no longer passed because of this change. Modified Paths: -------------- trunk/OpenMPT/mptrack/CleanupSong.cpp trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/mptrack/CleanupSong.cpp =================================================================== --- trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-02-02 22:36:22 UTC (rev 1512) +++ trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-02-03 20:58:24 UTC (rev 1513) @@ -575,20 +575,20 @@ SAMPLEINDEX numLoopOpt = 0; - for (SAMPLEINDEX nSmp = 1; nSmp <= pSndFile->GetNumSamples(); nSmp++) + for(SAMPLEINDEX smp = 1; smp <= pSndFile->GetNumSamples(); smp++) { - const ModSample &sample = pSndFile->GetSample(nSmp); + const ModSample &sample = pSndFile->GetSample(smp); // Determine how much of the sample will be played SmpLength loopLength = sample.nLength; - if(sample.uFlags & CHN_LOOP) + if(sample.uFlags[CHN_LOOP]) { loopLength = sample.nLoopEnd; + if(sample.uFlags[CHN_SUSTAINLOOP]) + { + loopLength = Util::Max(sample.nLoopEnd, sample.nSustainEnd); + } } - if(sample.uFlags & CHN_SUSTAINLOOP) - { - loopLength = Util::Max(sample.nLoopEnd, sample.nSustainEnd); - } if(sample.pSample && sample.nLength > loopLength + 2) numLoopOpt++; } @@ -605,12 +605,12 @@ // Determine how much of the sample will be played SmpLength loopLength = sample.nLength; - if(sample.uFlags & CHN_LOOP) + if(sample.uFlags[CHN_LOOP]) { loopLength = sample.nLoopEnd; // Sustain loop is played before normal loop, and it can actually be located after the normal loop. - if(sample.uFlags & CHN_SUSTAINLOOP) + if(sample.uFlags[CHN_SUSTAINLOOP]) { loopLength = Util::Max(sample.nLoopEnd, sample.nSustainEnd); } @@ -631,7 +631,7 @@ return true; } - return false; + return false; } // Rearrange sample list @@ -677,7 +677,7 @@ deleteInstrumentSamples removeSamples = doNoDeleteAssociatedSamples; if(!pSndFile->m_SongFlags[SONG_ITPROJECT]) // Never remove an instrument's samples in ITP. { - if(Reporting::Confirm("Remove samples associated with an instrument if they are unused?", "Removing unused instruments", false, false, this) == cnfYes) + if(Reporting::Confirm("Remove samples associated with unused instruments?", "Removing unused instruments", false, false, this) == cnfYes) { removeSamples = deleteAssociatedSamples; } Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2013-02-02 22:36:22 UTC (rev 1512) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2013-02-03 20:58:24 UTC (rev 1513) @@ -1139,12 +1139,12 @@ { const ModInstrument *pIns = pChn->pModInstrument; - if(IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) && pChn->VolEnv.nEnvPosition == 0) + if(IsCompatibleMode(TRK_IMPULSETRACKER) && pChn->VolEnv.nEnvPosition == 0) { // If the envelope is disabled at the very same moment as it is triggered, we do not process anything. return; } - const int envpos = pChn->VolEnv.nEnvPosition - (IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) ? 1 : 0); + const int envpos = pChn->VolEnv.nEnvPosition - (IsCompatibleMode(TRK_IMPULSETRACKER) ? 1 : 0); // Get values in [0, 256] int envval = Util::Round<int>(pIns->VolEnv.GetValueFromPosition(envpos) * 256.0f); @@ -1269,7 +1269,7 @@ } // Increase position - UINT position = chnEnv.nEnvPosition + (IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) ? 0 : 1); + UINT position = chnEnv.nEnvPosition + (IsCompatibleMode(TRK_IMPULSETRACKER) ? 0 : 1); const InstrumentEnvelope &insEnv = pChn->pModInstrument->GetEnvelope(envType); @@ -1371,7 +1371,7 @@ } } - chnEnv.nEnvPosition = position + (IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2) ? 1 : 0); + chnEnv.nEnvPosition = position + (IsCompatibleMode(TRK_IMPULSETRACKER) ? 1 : 0); } @@ -2027,7 +2027,7 @@ // Process Envelopes if (pIns) { - if(IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2)) + if(IsCompatibleMode(TRK_IMPULSETRACKER)) { // In IT and FT2 compatible mode, envelope position indices are shifted by one for proper envelope pausing, // so we have to update the position before we actually process the envelopes. @@ -2184,7 +2184,7 @@ } // Increment envelope positions - if (pIns != nullptr && !IsCompatibleMode(TRK_IMPULSETRACKER | TRK_FASTTRACKER2)) + if(pIns != nullptr && !IsCompatibleMode(TRK_IMPULSETRACKER)) { // In IT and FT2 compatible mode, envelope positions are updated above. // Test cases: s77.it, EnvLoops.xm This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-09 00:01:07
|
Revision: 1516 http://sourceforge.net/p/modplug/code/1516 Author: saga-games Date: 2013-02-09 00:00:57 +0000 (Sat, 09 Feb 2013) Log Message: ----------- [Imp] MOD Loader: Improved support for 15-sample (Ultimate Soundtracker and clones) modules. Original Ultimate Soundtracker effects are now handled better (e.g. in sll7.mod). [Mod] Cleanup: "Reset variables" also resets channel settings now. [Mod] OpenMPT: Version is now 1.21.01.10 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/mptrack/CleanupSong.cpp trunk/OpenMPT/soundlib/Load_mo3.cpp trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_umx.cpp trunk/OpenMPT/soundlib/ModChannel.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/common/version.h 2013-02-09 00:00:57 UTC (rev 1516) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 09 +#define VER_MINORMINOR 10 //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/CleanupSong.cpp =================================================================== --- trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-02-09 00:00:57 UTC (rev 1516) @@ -852,6 +852,11 @@ pSndFile->Instruments[i]->nResSwing = 0; } + for(CHANNELINDEX i = 0; i <= pSndFile->GetNumChannels(); i++) + { + pSndFile->ChnSettings[i].Reset(); + } + // reset samples ctrlSmp::ResetSamples(*pSndFile, ctrlSmp::SmpResetCompo); Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp 2013-02-09 00:00:57 UTC (rev 1516) @@ -87,7 +87,8 @@ || ReadIT(unpackedFile) || ReadS3M(unpackedFile) || ReadMTM(unpackedFile) - || ReadMod(unpackedFile); + || ReadMod(unpackedFile) + || ReadM15(unpackedFile); } UNMO3_Free(stream); Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-09 00:00:57 UTC (rev 1516) @@ -192,16 +192,9 @@ uint8 numOrders; uint8 restartPos; uint8 orderList[128]; - char magic[4]; - - // Check if header magic equals a given string. - bool IsMagic(const char *otherMagic) const - { - return (*reinterpret_cast<const uint32 *>(magic) == *reinterpret_cast<const uint32 *>(otherMagic)); - } }; -STATIC_ASSERT(sizeof(MODFileHeader) == 134); +STATIC_ASSERT(sizeof(MODFileHeader) == 130); // Sample Header @@ -363,13 +356,92 @@ }; +// Check if header magic equals a given string. +static bool IsMagic(const char *magic1, const char *magic2) +//--------------------------------------------------------- +{ + return (*reinterpret_cast<const uint32 *>(magic1) == *reinterpret_cast<const uint32 *>(magic2)); +} + + +static void ReadSample(FileReader &file, MODSampleHeader &sampleHeader, ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]) +//---------------------------------------------------------------------------------------------------------------------------- +{ + file.ReadConvertEndianness(sampleHeader); + sampleHeader.ConvertToMPT(sample); + + StringFixer::ReadString<StringFixer::spacePadded>(sampleName, sampleHeader.name); +} + + +// Parse the order list to determine how many patterns are used in the file. +static PATTERNINDEX GetNumPatterns(const FileReader &file, ModSequence &Order, ORDERINDEX numOrders, size_t totalSampleLen, CHANNELINDEX &numChannels, bool checkForWOW) +//---------------------------------------------------------------------------------------------------------------------------------------------------------------------- +{ + PATTERNINDEX numPatterns = 0; // Total number of patterns in file (determined by going through the whole order list) with pattern number < 128 + PATTERNINDEX officialPatterns = 0; // Number of patterns only found in the "official" part of the order list (i.e. order positions < claimed order length) + PATTERNINDEX numPatternsIllegal = 0; // Total number of patterns in file, also counting in "invalid" pattern indexes >= 128 + + for(ORDERINDEX ord = 0; ord < 128; ord++) + { + PATTERNINDEX pat = Order[ord]; + if(pat < 128 && numPatterns <= pat) + { + numPatterns = pat + 1; + if(ord < numOrders) + { + officialPatterns = numPatterns; + } + } + if(pat >= numPatternsIllegal) + { + numPatternsIllegal = pat + 1; + } + } + + // Fill order tail with stop patterns, now that we don't need the garbage in there anymore. + for(ORDERINDEX ord = numOrders; ord < 128; ord++) + { + Order[ord] = Order.GetInvalidPatIndex(); + } + + const size_t patternStartOffset = 20 + 31 * sizeof(MODSampleHeader) + sizeof(MODFileHeader) + 4; + const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset; + + if(checkForWOW) + { + // Check if this is a Mod's Grave WOW file... Never seen one of those, but apparently they *do* exist. + // Basically, WOW files seem to use the M.K. extensions, but are actually 8CHN files. + if(sizeWithoutPatterns + numPatterns * 8 * 256 == file.GetLength()) + { + numChannels = 8; + } + } + + // Now we have to check if the "hidden" patterns in the order list are actually real, i.e. if they are saved in the file. + if(numPatterns != officialPatterns && sizeWithoutPatterns + numPatterns * numChannels * 256 != file.GetLength()) + { + // Ok, size does not match the number of patterns including "hidden" patterns. Does it match the number of "official" patterns? + if(sizeWithoutPatterns + officialPatterns * numChannels * 256 == file.GetLength()) + { + // It does! Forget about that crap. + numPatterns = officialPatterns; + } + } else if(numPatternsIllegal > numPatterns && sizeWithoutPatterns + numPatternsIllegal * numChannels * 256 == file.GetLength()) + { + // Even those illegal pattern indexes (> 128) appear to be valid... What a weird file! + numPatterns = numPatternsIllegal; + } + + return numPatterns; +} + + bool CSoundFile::ReadMod(FileReader &file) //---------------------------------------- { - file.Rewind(); - - MODFileHeader fileHeader; - if(!file.Seek(20 + sizeof(MODSampleHeader) * 31) || !file.Read(fileHeader)) + char magic[4]; + if(!file.Seek(1080) || !file.ReadArray(magic)) { return false; } @@ -378,93 +450,67 @@ m_nChannels = 4; // Check MOD Magic - if(fileHeader.IsMagic("M.K.") // ProTracker and compatible - || fileHeader.IsMagic("M!K!") // ProTracker (64+ patterns) - || fileHeader.IsMagic("M&K!") // NoiseTracker - || fileHeader.IsMagic("N.T.") // NoiseTracker - || fileHeader.IsMagic("FEST")) // jobbig.mod by Mahoney + if(IsMagic(magic, "M.K.") // ProTracker and compatible + || IsMagic(magic, "M!K!") // ProTracker (64+ patterns) + || IsMagic(magic, "M&K!") // NoiseTracker + || IsMagic(magic, "N.T.") // NoiseTracker + || IsMagic(magic, "FEST")) // jobbig.mod by Mahoney { m_nChannels = 4; - } else if(fileHeader.IsMagic("CD81") // Falcon - || fileHeader.IsMagic("OKTA") // Oktalyzer - || fileHeader.IsMagic("OCTA")) // Oktalyzer + } else if(IsMagic(magic, "CD81") // Falcon + || IsMagic(magic, "OKTA") // Oktalyzer + || IsMagic(magic, "OCTA")) // Oktalyzer { m_nChannels = 8; - } else if((!memcmp(fileHeader.magic, "FLT", 3) || !memcmp(fileHeader.magic, "EXO", 3)) && fileHeader.magic[3] >= '4' && fileHeader.magic[3] <= '9') + } else if((!memcmp(magic, "FLT", 3) || !memcmp(magic, "EXO", 3)) && magic[3] >= '4' && magic[3] <= '9') { // FLTx / EXOx - Startrekker by Exolon / Fairlight - m_nChannels = fileHeader.magic[3] - '0'; - } else if(fileHeader.magic[0] >= '1' && fileHeader.magic[0] <= '9' && !memcmp(fileHeader.magic + 1, "CHN", 3)) + m_nChannels = magic[3] - '0'; + } else if(magic[0] >= '1' && magic[0] <= '9' && !memcmp(magic + 1, "CHN", 3)) { // xCHN - Many trackers - m_nChannels = fileHeader.magic[0] - '0'; - } else if(fileHeader.magic[0] >= '1' && fileHeader.magic[0] <= '9' && fileHeader.magic[1]>='0' && fileHeader.magic[1] <= '9' - && (!memcmp(fileHeader.magic + 2, "CH", 2) || !memcmp(fileHeader.magic + 2, "CN", 2))) + m_nChannels = magic[0] - '0'; + } else if(magic[0] >= '1' && magic[0] <= '9' && magic[1]>='0' && magic[1] <= '9' + && (!memcmp(magic + 2, "CH", 2) || !memcmp(magic + 2, "CN", 2))) { // xxCN / xxCH - Many trackers - m_nChannels = (fileHeader.magic[0] - '0') * 10 + fileHeader.magic[1] - '0'; - } else if(!memcmp(fileHeader.magic, "TDZ", 3) && fileHeader.magic[3] >= '4' && fileHeader.magic[3] <= '9') + m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0'; + } else if(!memcmp(magic, "TDZ", 3) && magic[3] >= '4' && magic[3] <= '9') { // TDZx - TakeTracker - m_nChannels = fileHeader.magic[3] - '0'; + m_nChannels = magic[3] - '0'; } else { - // Ultimate SoundTracker MODs - no magic bytes - m_nSamples = 15; + return false; } LimitMax(m_nChannels, MAX_BASECHANNELS); // Startrekker 8 channel mod (needs special treatment, see below) - bool isFLT8 = fileHeader.IsMagic("FLT8"); + bool isFLT8 = IsMagic(magic, "FLT8"); // Only apply VBlank tests to M.K. (ProTracker) modules. - const bool isMdKd = fileHeader.IsMagic("M.K."); + const bool isMdKd = IsMagic(magic, "M.K."); + // Reading song title + file.Seek(0); + file.ReadString<StringFixer::spacePadded>(m_szNames[0], 20); + // Load Samples - int m15Errors = 0; size_t totalSampleLen = 0; - file.Seek(20); - for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; - if(!file.ReadConvertEndianness(sampleHeader)) - { - return false; - } - sampleHeader.ConvertToMPT(Samples[smp]); + ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp]); - StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[smp], sampleHeader.name); - totalSampleLen += Samples[smp].nLength; - - // M15 Sanity checks - if(sampleHeader.volume > 256) - { - m15Errors++; - } - if(sampleHeader.length > 32768) - { - m15Errors++; - } - if(sampleHeader.finetune != 0) - { - m15Errors++; - } } - // Re-read file header, as it is found at another position in M15 files. + // Read order information + MODFileHeader fileHeader; file.Read(fileHeader); + file.Skip(4); // Magic bytes (we already parsed these) - // Sanity checks... - if(GetNumSamples() == 15) - { - if(totalSampleLen > file.GetLength() * 4 || fileHeader.numOrders > 128 || fileHeader.restartPos > 128) - { - return false; - } - } - Order.ReadFromArray(fileHeader.orderList); ORDERINDEX realOrders = fileHeader.numOrders; @@ -483,46 +529,8 @@ } // Do some order sanity checks + PATTERNINDEX numPatterns = GetNumPatterns(file, Order, realOrders, totalSampleLen, m_nChannels, isMdKd); - PATTERNINDEX numPatterns = 0; // Total number of patterns in file (determined by going through the whole order list) with pattern number < 128 - PATTERNINDEX officialPatterns = 0; // Number of patterns only found in the "official" part of the order list (i.e. order positions < claimed order length) - PATTERNINDEX numPatternsIllegal = 0; // Total number of patterns in file, also counting in "invalid" pattern indexes >= 128 - - for(ORDERINDEX ord = 0; ord < 128; ord++) - { - PATTERNINDEX pat = Order[ord]; - if(pat < 128 && numPatterns <= pat) - { - numPatterns = pat + 1; - if(ord < realOrders) - { - officialPatterns = numPatterns; - } - } - if(pat >= numPatternsIllegal) - { - numPatternsIllegal = pat + 1; - } - - // From mikmod: if the file says FLT8, but the orderlist has odd numbers, it's probably really an FLT4 - if(isFLT8 && (Order[ord] % 2u) != 0) - { - m_nChannels = 4; - isFLT8 = false; - } - - // chances are very high that we're dealing with a non-MOD file here. - if(GetNumSamples() == 15 && pat >= 64) - { - return false; - } - } - - if(!numPatterns) - { - return false; - } - if(isFLT8) { // FLT8 has only even order items, so divide by two. @@ -531,13 +539,7 @@ Order[ord] /= 2; } } - - // Fill order tail with stop patterns - for(ORDERINDEX ord = realOrders; ord < 128; ord++) - { - Order[ord] = Order.GetInvalidPatIndex(); - } - + // Restart position sanity checks realOrders--; m_nRestartPos = fileHeader.restartPos; @@ -551,60 +553,15 @@ m_nRestartPos = 0; } - const size_t patternStartOffset = 20 + GetNumSamples() * sizeof(MODSampleHeader) + sizeof(MODFileHeader) - (GetNumSamples() == 15 ? 4 : 0); - const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset; - - if(isMdKd) - { - // Check if this is a Mod's Grave WOW file... Never seen one of those, but apparently they *do* exist. - // Basically, WOW files seem to use the M.K. extensions, but are actually 8CHN files. - if(sizeWithoutPatterns + numPatterns * 8 * 256 == file.GetLength()) - { - m_nChannels = 8; - } - } - - // Now we have to check if the "hidden" patterns in the order list are actually real, i.e. if they are saved in the file. - if(numPatterns != officialPatterns && sizeWithoutPatterns + numPatterns * m_nChannels * 256 != file.GetLength()) - { - // Ok, size does not match the number of patterns including "hidden" patterns. Does it match the number of "official" patterns? - if(sizeWithoutPatterns + officialPatterns * m_nChannels * 256 == file.GetLength()) - { - // It does! Forget about that crap. - numPatterns = officialPatterns; - } else - { - // Well... Neither fits... So this must be a broken file. - m15Errors += 8; - } - } else if(numPatternsIllegal > numPatterns && sizeWithoutPatterns + numPatternsIllegal * m_nChannels * 256 == file.GetLength()) - { - // Even those illegal pattern indexes (> 128) appear to be valid... What a weird file! - numPatterns = numPatternsIllegal; - } - - // Some final M15 sanity checks... - if(sizeWithoutPatterns < 0x600 || sizeWithoutPatterns > file.GetLength()) - { - m15Errors += 8; - } - - if(GetNumSamples() == 15 && m15Errors >= 16) - { - return false; - } - // Now we can be pretty sure that this is a valid MOD file. Set up default song settings. m_nType = MOD_TYPE_MOD; + m_nInstruments = 0; m_nDefaultSpeed = 6; m_nDefaultTempo = 125; m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; m_SongFlags.reset(); - file.Seek(0); - file.ReadString<StringFixer::spacePadded>(m_szNames[0], 20); - // Setup channel pan positions and volume SetupMODPanning(); @@ -613,8 +570,6 @@ bool hasTempoCommands = false; // for detecting VBlank MODs bool leftPanning = false, extendedPanning = false; // for detecting 800-880 panning - file.Seek(patternStartOffset); - // Reading patterns for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { @@ -705,7 +660,7 @@ } // Reading samples - for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) + for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader::GetSampleFormat().ReadSample(Samples[smp], file); } @@ -720,8 +675,7 @@ // In the pattern loader above, a second condition is used: Only tempo commands // below 100 BPM are taken into account. Furthermore, only M.K. (ProTracker) // modules are checked. - // The same check is also applied to original Ultimate Soundtracker 15 sample mods. - const bool fixVBlank = ((isMdKd && hasTempoCommands && GetSongTime() >= 10 * 60) || GetNumSamples()== 15); + const bool fixVBlank = isMdKd && hasTempoCommands && GetSongTime() >= 10 * 60; const bool fix7BitPanning = leftPanning && !extendedPanning; if(fixVBlank || fix7BitPanning) { @@ -732,6 +686,286 @@ } +// Check if a name string is valid (i.e. doesn't contain binary garbage data) +static bool IsValidName(const char *s, size_t length, char minChar) +//----------------------------------------------------------------- +{ + size_t i; + // Check for garbage characters + for(i = 0; i < length; i++) + { + if(s[i] && s[i] < minChar) + { + return false; + } + } + // Check for garbage after null terminator. + i = static_cast<const char *>(memchr(s, '\0', length)) - s; + for(; i < length; i++) + { + if(s[i]) + { + return false; + } + } + return true; +} + + +bool CSoundFile::ReadM15(FileReader &file) +//---------------------------------------- +{ + file.Rewind(); + + char songname[20]; + file.ReadArray(songname); + if(!IsValidName(songname, sizeof(songname), 32) + || file.BytesLeft() < sizeof(MODSampleHeader) * 15 + sizeof(MODFileHeader)) + { + return false; + } + + // We'll have to do some heuristic checks to find out whether this is an old Ultimate Soundtracker module + // or if it was made with the newer Soundtracker versions. + bool isUST = false, isConfirmed = false; + + size_t totalSampleLen = 0; + for(SAMPLEINDEX smp = 1; smp <= 15; smp++) + { + MODSampleHeader sampleHeader; + ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp]); + + // Sanity checks + if(!IsValidName(sampleHeader.name, sizeof(sampleHeader.name), 14) + || sampleHeader.volume > 64 + || (sampleHeader.finetune >> 4) != 0 + || sampleHeader.length > 32768) + { + return false; + } + + totalSampleLen += Samples[smp].nLength; + + if(isConfirmed) + { + continue; + } + + // Soundtracker sample names should always start with "S", "ST-" or a number, but for UST mods, this is not the case. + if(sampleHeader.name[0] == 's'|| sampleHeader.name[0] == 'S') + { + if(sampleHeader.name[0] + && memcmp(sampleHeader.name,"st-",3) + && memcmp(sampleHeader.name,"ST-",3)) + { + isUST = true; + } + } else if(sampleHeader.name[0] < '0' || sampleHeader.name[0] > '9') + { + isUST = true; + } + + // UST only handles samples up to 9999 bytes. + if(sampleHeader.length > 4999 || sampleHeader.loopStart > 9999) + { + isUST = false; + } + // If loop information is incorrect as words, but correct as bytes, this is likely to be an UST-style module + if(sampleHeader.loopStart + sampleHeader.loopLength > sampleHeader.length + && sampleHeader.loopStart + sampleHeader.loopLength < sampleHeader.length * 2) + { + isUST = true; + isConfirmed = true; + continue; + } + + if(!isUST) + { + isConfirmed = true; + } + } + + MODFileHeader fileHeader; + file.Read(fileHeader); + + // Sanity check: No more than 128 positions, restart position is valid (although there are some weird values that we need to ignore). + if(fileHeader.numOrders > 128 + || ((fileHeader.restartPos & 0xF8) != 0x78 && fileHeader.restartPos != 0x6A && fileHeader.restartPos > fileHeader.numOrders)) + { + return false; + } + + for(ORDERINDEX ord = 0; ord < CountOf(fileHeader.orderList); ord++) + { + // Sanity check: 64 patterns max. + if(fileHeader.orderList[ord] > 63) + { + return false; + } + } + + Order.ReadFromArray(fileHeader.orderList); + PATTERNINDEX numPatterns = GetNumPatterns(file, Order, fileHeader.numOrders, totalSampleLen, m_nChannels, false); + + // Let's see if the file is too small (including some overhead for broken files like sll7.mod) + if(file.BytesLeft() + 4096 < numPatterns * 64u * 4u + totalSampleLen) + { + return false; + } + + // Now we can be pretty sure that this is a valid Soundtracker file. Set up default song settings. + m_nType = MOD_TYPE_MOD; + m_nChannels = 4; + m_nSamples = 15; + m_nInstruments = 0; + m_nDefaultSpeed = 6; + m_nDefaultTempo = 125; + m_nMinPeriod = 14 * 4; + m_nMaxPeriod = 3424 * 4; + m_SongFlags.reset(); + m_nRestartPos = fileHeader.restartPos; + StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], songname); + + // Setup channel pan positions and volume + SetupMODPanning(); + + if(!isConfirmed) + { + FileReader::off_t patOffset = file.GetPosition(); + + // Scan patterns to identify Ultimate Soundtracker modules. + for(size_t i = 0; i < numPatterns * 64u * 4u; i++) + { + uint8 data[4]; + file.ReadArray(data); + + if((data[2] == 1 || data[2] == 2) && data[3] > 0x1F) + { + // If a 1xx effect has a parameter greater than 0x20, it is assumed to be UST. + isUST = true; + break; + } else if(data[2] == 1 && data[3] < 0x03) + { + // MikMod says so! Well, it makes sense, kind of... who would want an arpeggio like this? + isUST = false; + break; + } else if(data[2] == 3 && data[3] != 0) + { + // MikMod says so! + isUST = false; + break; + } else if((data[2] & 0x0F) > 3) + { + // Unknown effect + isUST = false; + break; + } + } + file.Seek(patOffset); + } + + // Reading patterns + for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) + { + if(Patterns.Insert(pat, 64)) + { + break; + } + + uint8 lastEff[4] = { 0, 0, 0, 0 }, lastParam[4] = { 0, 0, 0, 0 }; + + for(ROWINDEX row = 0; row < 64; row++) + { + ModCommand *rowBase = Patterns[pat].GetpModCommand(row, 0); + for(CHANNELINDEX chn = 0; chn < 4; chn++) + { + ModCommand &m = rowBase[chn]; + + uint8 data[4]; + file.ReadArray(data); + + // Read Period + uint16 period = (((static_cast<uint16>(data[0]) & 0x0F) << 8) | data[1]); + if(period > 0 && period != 0xFFF) + { + m.note = static_cast<ModCommand::NOTE>(GetNoteFromPeriod(period * 4)); + } + // Read Instrument + m.instr = (data[2] >> 4) | (data[0] & 0x10); + // Read Effect + m.command = data[2] & 0x0F; + m.param = data[3]; + + if(m.command || m.param) + { + if(isUST) + { + // UST effects + switch(m.command) + { + case 0: + case 3: + m.command = CMD_NONE; + break; + case 1: + m.command = CMD_ARPEGGIO; + break; + case 2: + if(m.param & 0x0F) + { + m.command = CMD_PORTAMENTOUP; + m.param &= 0x0F; + } else if(m.param >> 2) + { + m.command = CMD_PORTAMENTODOWN; + m.param >>= 2; + } + break; + default: + ConvertModCommand(m); + break; + } + } else + { + // M15 effects + if((m.command == 1 || m.command == 2 || m.command == 3) && m.param == 0) + { + // An isolated 100, 200 or 300 effect should be ignored (no "standalone" porta memory in mod files). + // However, a sequence such as 1xx, 100, 100, 100 is fine. + if(m.command != lastEff[chn] || lastParam[chn] == 0) + { + m.command = m.param = 0; + } else + { + m.param = lastParam[chn]; + } + } + lastEff[chn] = m.command; + lastParam[chn] = m.param; + + ConvertModCommand(m); + } + + if(m.command == CMD_TEMPO) + { + // No CIA timing! + m.command = CMD_SPEED; + } + } + } + } + } + + // Reading samples + for(SAMPLEINDEX smp = 1; smp <= 15; smp++) + { + MODSampleHeader::GetSampleFormat().ReadSample(Samples[smp], file); + } + + return true; +} + + #ifndef MODPLUG_NO_FILESAVE #ifdef MODPLUG_TRACKER @@ -812,28 +1046,29 @@ { fileHeader.restartPos = static_cast<uint8>(m_nRestartPos); } + fwrite(&fileHeader, sizeof(fileHeader), 1, f); // Write magic bytes + char magic[4]; CHANNELINDEX writeChannels = min(99, GetNumChannels()); if(writeChannels == 4) { if(writePatterns < 64) { - memcpy(fileHeader.magic, "M.K.", 4); + memcpy(magic, "M.K.", 4); } else { // More than 64 patterns - memcpy(fileHeader.magic, "M!K!", 4); + memcpy(magic, "M!K!", 4); } } else { char magic[6]; sprintf(magic, "%luCHN", writeChannels); - memcpy(fileHeader.magic, magic, 4); + memcpy(magic, magic, 4); } + fwrite(&magic, sizeof(magic), 1, f); - fwrite(&fileHeader, sizeof(fileHeader), 1, f); - // Write patterns vector<uint8> events; for(PATTERNINDEX pat = 0; pat < writePatterns; pat++) Modified: trunk/OpenMPT/soundlib/Load_umx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_umx.cpp 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/soundlib/Load_umx.cpp 2013-02-09 00:00:57 UTC (rev 1516) @@ -276,7 +276,8 @@ || ReadSTM(fileChunk) || Read669(fileChunk) || ReadFAR(fileChunk) - || ReadMod(fileChunk)) + || ReadMod(fileChunk) + || ReadM15(fileChunk)) { return true; } Modified: trunk/OpenMPT/soundlib/ModChannel.h =================================================================== --- trunk/OpenMPT/soundlib/ModChannel.h 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/soundlib/ModChannel.h 2013-02-09 00:00:57 UTC (rev 1516) @@ -183,6 +183,11 @@ ModChannelSettings() { + Reset(); + } + + void Reset() + { nPan = 128; nVolume = 64; nMixPlugin = 0; Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-09 00:00:57 UTC (rev 1516) @@ -2058,7 +2058,7 @@ // Helper function for copying OpenMPT's sample data to FLAC's int32 buffer. template<typename T> -inline void SampleToFLAC32(FLAC__int32 *dst, const void *src, SmpLength numSamples) +inline static void SampleToFLAC32(FLAC__int32 *dst, const void *src, SmpLength numSamples) { const T *in = reinterpret_cast<const T *>(src); for(SmpLength i = 0; i < numSamples; i++) Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-09 00:00:57 UTC (rev 1516) @@ -638,7 +638,8 @@ && !ReadAM(file) && !ReadJ2B(file) && !ReadMO3(file) - && !ReadMod(file)) + && !ReadMod(file) + && !ReadM15(file)) { m_nType = MOD_TYPE_NONE; } @@ -1549,22 +1550,6 @@ } -bool CSoundFile::MoveSample(SAMPLEINDEX from, SAMPLEINDEX to) -//----------------------------------------------------------- -{ - if (!from || from >= MAX_SAMPLES || !to || to >= MAX_SAMPLES) return false; - if (/*!Ins[from].pSample ||*/ Samples[to].pSample) return true; - - Samples[to] = Samples[from]; - - Samples[from].pSample = nullptr; - Samples[from].nLength = 0; - Samples[from].uFlags.reset(CHN_16BIT | CHN_STEREO); - - return true; -} - - void CSoundFile::DeleteStaticdata() //--------------------------------- { Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-07 00:39:58 UTC (rev 1515) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-09 00:00:57 UTC (rev 1516) @@ -389,6 +389,7 @@ bool ReadXM(FileReader &file); bool ReadS3M(FileReader &file); bool ReadMod(FileReader &file); + bool ReadM15(FileReader &file); bool ReadMed(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadMTM(FileReader &file); bool ReadSTM(FileReader &file); @@ -466,7 +467,7 @@ BOOL FadeSong(UINT msec); BOOL GlobalFadeSong(UINT msec); void ProcessPlugins(UINT nCount); - size_t GetTotalSampleCount() const { return m_lTotalSampleCount; } + samplecount_t GetTotalSampleCount() const { return m_lTotalSampleCount; } bool HasPositionChanged() { bool b = m_bPositionChanged; m_bPositionChanged = false; return b; } public: @@ -604,11 +605,6 @@ public: bool DestroySample(SAMPLEINDEX nSample); -// -> CODE#0020 -// -> DESC="rearrange sample list" - bool MoveSample(SAMPLEINDEX from, SAMPLEINDEX to); -// -! NEW_FEATURE#0020 - // Find an unused sample slot. If it is going to be assigned to an instrument, targetInstrument should be specified. // SAMPLEINDEX_INVLAID is returned if no free sample slot could be found. SAMPLEINDEX GetNextFreeSample(INSTRUMENTINDEX targetInstrument = INSTRUMENTINDEX_INVALID, SAMPLEINDEX start = 1) const; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-11 21:57:15
|
Revision: 1518 http://sourceforge.net/p/modplug/code/1518 Author: saga-games Date: 2013-02-11 21:57:08 +0000 (Mon, 11 Feb 2013) Log Message: ----------- [Ref] Small code changes. [Fix] Note slide up/down were missing from the string of supported effects in the mod specs and were thus not drawn correctly. Modified Paths: -------------- trunk/OpenMPT/mptrack/Draw_pat.cpp trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/soundlib/RowVisitor.cpp Modified: trunk/OpenMPT/mptrack/Draw_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/Draw_pat.cpp 2013-02-09 15:47:25 UTC (rev 1517) +++ trunk/OpenMPT/mptrack/Draw_pat.cpp 2013-02-11 21:57:08 UTC (rev 1518) @@ -479,7 +479,7 @@ else { static_assert(MAX_VOLCMDS <= 16, "Pattern draw code assumes <= 16 volume commands"); - int volcmd = (mc.volcmd & 0x0F); + ModCommand::VOLCMD volcmd = (mc.volcmd & 0x0F); int vol = (mc.vol & 0x7F); if(drawDefaultVolume) @@ -507,14 +507,14 @@ } } - if (volcmd) + if(volcmd != VOLCMD_NONE) { m_Dib.TextBlt(x, y, pfnt->nVolCmdWidth, COLUMN_HEIGHT, - pfnt->nVolX, pfnt->nVolY+volcmd*COLUMN_HEIGHT); + pfnt->nVolX, pfnt->nVolY + volcmd * COLUMN_HEIGHT); m_Dib.TextBlt(x+pfnt->nVolCmdWidth, y, pfnt->nVolHiWidth, COLUMN_HEIGHT, - pfnt->nNumX, pfnt->nNumY+(vol / 10)*COLUMN_HEIGHT); - m_Dib.TextBlt(x+pfnt->nVolCmdWidth+pfnt->nVolHiWidth, y, pfnt->nEltWidths[2]-(pfnt->nVolCmdWidth+pfnt->nVolHiWidth), COLUMN_HEIGHT, - pfnt->nNumX, pfnt->nNumY+(vol % 10)*COLUMN_HEIGHT); + pfnt->nNumX, pfnt->nNumY + (vol / 10) * COLUMN_HEIGHT); + m_Dib.TextBlt(x+pfnt->nVolCmdWidth + pfnt->nVolHiWidth, y, pfnt->nEltWidths[2] - (pfnt->nVolCmdWidth + pfnt->nVolHiWidth), COLUMN_HEIGHT, + pfnt->nNumX, pfnt->nNumY + (vol % 10) * COLUMN_HEIGHT); } else { int srcx = pfnt->nEltWidths[0] + pfnt->nEltWidths[1]; @@ -1044,7 +1044,7 @@ uint16 val = m->GetValueEffectCol(); if(val > ModCommand::maxColumnValue) val = ModCommand::maxColumnValue; fx_col = row_col; - if (!isPCnote && (m->command) && (m->command < MAX_EFFECTS) && (CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_EFFECTHILIGHT)) + if (!isPCnote && m->command != CMD_NONE && m->command < MAX_EFFECTS && (CMainFrame::GetSettings().m_dwPatternSetup & PATTERN_EFFECTHILIGHT)) { if(effectColors[m->command] != 0) fx_col = effectColors[m->command]; @@ -1065,15 +1065,13 @@ { m_Dib.TextBlt(xbmp + x, 0, 2, COLUMN_HEIGHT, pfnt->nClrX+x, pfnt->nClrY); m_Dib.TextBlt(xbmp + x + 2, 0, pfnt->nEltWidths[3], m_szCell.cy, pfnt->nNumX, pfnt->nNumY+(val / 100)*COLUMN_HEIGHT); - } - else + } else { - if (m->command) + if(m->command != CMD_NONE) { - ModCommand::COMMAND command = m->command & 0x3F; - int n = pSndFile->GetModSpecifications().GetEffectLetter(command); + char n = pSndFile->GetModSpecifications().GetEffectLetter(m->command); ASSERT(n > ' '); - DrawLetter(xbmp+x, 0, (char)n, pfnt->nEltWidths[3], pfnt->nCmdOfs); + DrawLetter(xbmp+x, 0, n, pfnt->nEltWidths[3], pfnt->nCmdOfs); } else { m_Dib.TextBlt(xbmp+x, 0, pfnt->nEltWidths[3], COLUMN_HEIGHT, pfnt->nClrX+x, pfnt->nClrY); Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2013-02-09 15:47:25 UTC (rev 1517) +++ trunk/OpenMPT/mptrack/test/test.cpp 2013-02-11 21:57:08 UTC (rev 1518) @@ -264,8 +264,15 @@ //Util::Round<uint64>(1.0); // This should trigger assert in Round. - //VERIFY_EQUAL( Util::Round<int8>(-129), 0 ); + //VERIFY_EQUAL( Util::Round<int8>(-129), 0 ); + // Check for completeness of supported effect list in mod specifications + for(size_t i = 0; i < CountOf(ModSpecs::Collection); i++) + { + ASSERT(strlen(ModSpecs::Collection[i]->commands) == MAX_EFFECTS); + ASSERT(strlen(ModSpecs::Collection[i]->volcommands) == MAX_VOLCMDS); + } + } @@ -315,7 +322,7 @@ // Check if our test file was loaded correctly. void TestLoadXMFile(const CModDoc *pModDoc) -//--------------------------------------- +//----------------------------------------- { const CSoundFile *pSndFile = pModDoc->GetSoundFile(); Modified: trunk/OpenMPT/soundlib/RowVisitor.cpp =================================================================== --- trunk/OpenMPT/soundlib/RowVisitor.cpp 2013-02-09 15:47:25 UTC (rev 1517) +++ trunk/OpenMPT/soundlib/RowVisitor.cpp 2013-02-11 21:57:08 UTC (rev 1518) @@ -13,7 +13,7 @@ * there's no problem with (infinite) pattern loops in this code. * * Normal player code: - * Bare in mind that rows inside pattern loops should only be evaluated once, or else the algorithm will cancel too early! + * Bear in mind that rows inside pattern loops should only be evaluated once, or else the algorithm will cancel too early! * So in that case, the pattern loop rows have to be reset when looping back. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. @@ -177,10 +177,10 @@ // Unvisit all rows that are in the visited row buffer, until we hit the start row for this pattern loop. ROWINDEX row = ROWINDEX_INVALID; - while(!visitOrder.empty() && row != startRow) + vector<ROWINDEX>::reverse_iterator iter = visitOrder.rbegin(); + while(iter != visitOrder.rend() && row != startRow) { - row = visitOrder.back(); - visitOrder.pop_back(); + row = *(iter++); Unvisit(order, row); } visitOrder.clear(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-11 21:58:12
|
Revision: 1519 http://sourceforge.net/p/modplug/code/1519 Author: saga-games Date: 2013-02-11 21:58:06 +0000 (Mon, 11 Feb 2013) Log Message: ----------- [Imp] MOD Loader: Improved heuristics for 15-sample MODs. [Mod] OpenMPT: Version is now 1.21.01.11 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/soundlib/Load_mod.cpp Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-02-11 21:57:08 UTC (rev 1518) +++ trunk/OpenMPT/common/version.h 2013-02-11 21:58:06 UTC (rev 1519) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 10 +#define VER_MINORMINOR 11 //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_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-11 21:57:08 UTC (rev 1518) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-11 21:58:06 UTC (rev 1519) @@ -32,8 +32,13 @@ case 0x0C: m.command = CMD_VOLUME; break; case 0x0D: m.command = CMD_PATTERNBREAK; m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break; case 0x0E: m.command = CMD_MODCMDEX; break; - case 0x0F: m.command = static_cast<ModCommand::COMMAND>((m.param <= ((GetType() & (MOD_TYPE_MOD)) ? 0x20u : 0x1Fu)) ? CMD_SPEED : CMD_TEMPO); - if ((m.param == 0xFF) && (GetNumSamples() == 15) && (GetType() & MOD_TYPE_MOD)) m.command = CMD_NONE; break; //<rewbs> what the hell is this?! :) //<jojo> it's the "stop tune" command! :-P + case 0x0F: + // Speed is 01...1F in XM, but 01...20 in MOD. 15-sample Soundtracker MODs always use VBlank timing, interpret all values as speed. + if(((GetType() & MOD_TYPE_MOD) && (GetNumSamples() == 15 || m.param <= 0x20u)) || (!(GetType() & MOD_TYPE_MOD) && m.param <= 0x1Fu)) + m.command = CMD_SPEED; + else + m.command = CMD_TEMPO; + break; // Extension for XM extended effects case 'G' - 55: m.command = CMD_GLOBALVOLUME; break; //16 @@ -234,12 +239,12 @@ mptSmp.nLoopStart = lStart; mptSmp.nLoopEnd = lStart + lLength; - if (mptSmp.nLength == 2) + if(mptSmp.nLength == 2) { mptSmp.nLength = 0; } - if (mptSmp.nLength) + if(mptSmp.nLength) { if(mptSmp.nLoopStart >= mptSmp.nLength) { @@ -333,14 +338,13 @@ void operator()(ModCommand &m) { - // Fix VBlank MODs if(m.command == CMD_TEMPO && this->fixVBlank) { + // Fix VBlank MODs m.command = CMD_SPEED; - } - // Fix MODs with 7-bit + surround panning - if(m.command == CMD_PANNING8 && this->fixPanning) + } else if(m.command == CMD_PANNING8 && this->fixPanning) { + // Fix MODs with 7-bit + surround panning if(m.param == 0xA4) { m.command = CMD_S3MCMDEX; @@ -446,7 +450,6 @@ return false; } - m_nSamples = 31; m_nChannels = 4; // Check MOD Magic @@ -497,7 +500,7 @@ // Load Samples size_t totalSampleLen = 0; - + m_nSamples = 31; for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { MODSampleHeader sampleHeader; @@ -703,7 +706,7 @@ i = static_cast<const char *>(memchr(s, '\0', length)) - s; for(; i < length; i++) { - if(s[i]) + if(s[i] && s[i] < ' ') { return false; } @@ -719,7 +722,7 @@ char songname[20]; file.ReadArray(songname); - if(!IsValidName(songname, sizeof(songname), 32) + if(!IsValidName(songname, sizeof(songname), ' ') || file.BytesLeft() < sizeof(MODSampleHeader) * 15 + sizeof(MODFileHeader)) { return false; @@ -730,6 +733,7 @@ bool isUST = false, isConfirmed = false; size_t totalSampleLen = 0; + m_nSamples = 15; for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { MODSampleHeader sampleHeader; @@ -752,16 +756,9 @@ } // Soundtracker sample names should always start with "S", "ST-" or a number, but for UST mods, this is not the case. - if(sampleHeader.name[0] == 's'|| sampleHeader.name[0] == 'S') + // sll17.3.mod from ModLand has Soundtracker pattern effects but no "st-" sample names. Is this a bad / modified rip? + if((memcmp(sampleHeader.name, "st-", 3) && memcmp(sampleHeader.name, "ST-", 3)) || sampleHeader.name[0] < '0' || sampleHeader.name[0] > '9') { - if(sampleHeader.name[0] - && memcmp(sampleHeader.name,"st-",3) - && memcmp(sampleHeader.name,"ST-",3)) - { - isUST = true; - } - } else if(sampleHeader.name[0] < '0' || sampleHeader.name[0] > '9') - { isUST = true; } @@ -788,9 +785,8 @@ MODFileHeader fileHeader; file.Read(fileHeader); - // Sanity check: No more than 128 positions, restart position is valid (although there are some weird values that we need to ignore). - if(fileHeader.numOrders > 128 - || ((fileHeader.restartPos & 0xF8) != 0x78 && fileHeader.restartPos != 0x6A && fileHeader.restartPos > fileHeader.numOrders)) + // Sanity check: No more than 128 positions. We won't check the restart pos since I've encountered so many invalid values (0x6A, 0x72, 0x78, ...) that it doesn't make sense to check for them all. + if(fileHeader.numOrders > 128) { return false; } @@ -816,54 +812,52 @@ // Now we can be pretty sure that this is a valid Soundtracker file. Set up default song settings. m_nType = MOD_TYPE_MOD; m_nChannels = 4; - m_nSamples = 15; m_nInstruments = 0; m_nDefaultSpeed = 6; m_nDefaultTempo = 125; m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; m_SongFlags.reset(); - m_nRestartPos = fileHeader.restartPos; + m_nRestartPos = (fileHeader.restartPos < fileHeader.numOrders ? fileHeader.restartPos : 0); StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], songname); // Setup channel pan positions and volume SetupMODPanning(); - if(!isConfirmed) + FileReader::off_t patOffset = file.GetPosition(); + + // Scan patterns to identify Ultimate Soundtracker modules. + for(size_t i = 0; i < numPatterns * 64u * 4u; i++) { - FileReader::off_t patOffset = file.GetPosition(); + uint8 data[4]; + file.ReadArray(data); + const uint8 eff = data[2] & 0x0F, param = data[3]; - // Scan patterns to identify Ultimate Soundtracker modules. - for(size_t i = 0; i < numPatterns * 64u * 4u; i++) + if((eff == 1 || eff == 2) && param > 0x1F) { - uint8 data[4]; - file.ReadArray(data); - - if((data[2] == 1 || data[2] == 2) && data[3] > 0x1F) - { - // If a 1xx effect has a parameter greater than 0x20, it is assumed to be UST. - isUST = true; - break; - } else if(data[2] == 1 && data[3] < 0x03) - { - // MikMod says so! Well, it makes sense, kind of... who would want an arpeggio like this? - isUST = false; - break; - } else if(data[2] == 3 && data[3] != 0) - { - // MikMod says so! - isUST = false; - break; - } else if((data[2] & 0x0F) > 3) - { - // Unknown effect - isUST = false; - break; - } + // If a 1xx effect has a parameter greater than 0x20, it is assumed to be UST. + isUST = true; + break; + } else if(eff == 1 && param < 0x03) + { + // MikMod says so! Well, it makes sense, kind of... who would want an arpeggio like this? + isUST = false; + break; + } else if(eff == 3 && param != 0) + { + // MikMod says so! + isUST = false; + break; + } else if(eff > 3) + { + // Unknown effect + isUST = false; + break; } - file.Seek(patOffset); } + file.Seek(patOffset); + // Reading patterns for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) { @@ -945,12 +939,6 @@ ConvertModCommand(m); } - - if(m.command == CMD_TEMPO) - { - // No CIA timing! - m.command = CMD_SPEED; - } } } } @@ -959,6 +947,15 @@ // Reading samples for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { + if(isUST) + { + // Looped samples in Ultimate Soundtracker seem to ignore all sample data before the actual loop start. + // This avoids the clicks in the first sample of pretend.mod by Karsten Obarski. + file.Skip(Samples[smp].nLoopStart); + Samples[smp].nLength -= Samples[smp].nLoopStart; + Samples[smp].nLoopEnd -= Samples[smp].nLoopStart; + Samples[smp].nLoopStart = 0; + } MODSampleHeader::GetSampleFormat().ReadSample(Samples[smp], file); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-11 22:35:35
|
Revision: 1521 http://sourceforge.net/p/modplug/code/1521 Author: saga-games Date: 2013-02-11 22:35:29 +0000 (Mon, 11 Feb 2013) Log Message: ----------- [Ref] Changed SNDMIXPLUGIN struct so that we don't have to do that bit fiddling with dwInputRouting all the time. Modified Paths: -------------- trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/soundlib/plugins/PlugInterface.h Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2013-02-11 22:31:02 UTC (rev 1520) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2013-02-11 22:35:29 UTC (rev 1521) @@ -773,7 +773,7 @@ if(plugin.pMixPlugin) { - DWORD gain = nPos; + uint8 gain = (uint8)nPos; if(gain == 0) gain = 1; plugin.SetGain(gain); @@ -1192,7 +1192,7 @@ if ((m_nCurrentPlugin >= MAX_MIXPLUGINS) || (!pModDoc)) return; pSndFile = pModDoc->GetSoundFile(); - pSndFile->m_MixPlugins[m_nCurrentPlugin].SetMixMode(m_CbnSpecialMixProcessing.GetCurSel()); // update#02 (fix) + pSndFile->m_MixPlugins[m_nCurrentPlugin].SetMixMode((uint8)m_CbnSpecialMixProcessing.GetCurSel()); if(pSndFile->GetModSpecifications().supportsPlugins) pModDoc->SetModified(); } Modified: trunk/OpenMPT/soundlib/plugins/PlugInterface.h =================================================================== --- trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2013-02-11 22:31:02 UTC (rev 1520) +++ trunk/OpenMPT/soundlib/plugins/PlugInterface.h 2013-02-11 22:35:29 UTC (rev 1521) @@ -109,21 +109,23 @@ VstInt32 dwPluginId1; // Plugin type (kEffectMagic, kDmoMagic, kBuzzMagic) VstInt32 dwPluginId2; // Plugin unique ID - uint32 dwInputRouting; // Bits 0 to 7 = RoutingFlags, bits 8 - 15 = mixing mode, bits 16-23 = gain + uint8 routingFlags; // See RoutingFlags + uint8 mixMode; + uint8 gain; // Divide by 10 to get real gain + uint8 reserved; uint32 dwOutputRouting; // 0 = send to master 0x80 + x = send to plugin x uint32 dwReserved[4]; // Reserved for routing info CHAR szName[32]; // User-chosen plugin name CHAR szLibraryName[64]; // original DLL name // Should only be called from SNDMIXPLUGIN::SetBypass() and IMixPlugin::Bypass() - void SetBypass(bool bypass = true) { if(bypass) dwInputRouting |= irBypass; else dwInputRouting &= ~irBypass; }; + void SetBypass(bool bypass = true) { if(bypass) routingFlags |= irBypass; else routingFlags &= ~irBypass; } // Convert all multi-byte numeric values to current platform's endianness or vice versa. void ConvertEndianness() { SwapBytesLE(dwPluginId1); SwapBytesLE(dwPluginId2); - SwapBytesLE(dwInputRouting); SwapBytesLE(dwOutputRouting); SwapBytesLE(dwReserved[0]); SwapBytesLE(dwReserved[1]); @@ -142,57 +144,57 @@ ULONG nPluginDataSize; void *pPluginData; SNDMIXPLUGININFO Info; - float fDryRatio; // rewbs.dryRatio [20040123] - long defaultProgram; // rewbs.plugDefaultProgram + float fDryRatio; + VstInt32 defaultProgram; const char *GetName() const { return Info.szName; } const char *GetLibraryName() const - { return Info.szLibraryName; }; + { return Info.szLibraryName; } CString GetParamName(PlugParamIndex index) const; // Check if a plugin is loaded into this slot (also returns true if the plugin in this slot has not been found) bool IsValidPlugin() const { return (Info.dwPluginId1 | Info.dwPluginId2) != 0; }; // Input routing getters - int GetGain() const - { return (Info.dwInputRouting >> 16) & 0xFF; }; - int GetMixMode() const - { return (Info.dwInputRouting >> 8) & 0xFF; }; + uint8 GetGain() const + { return Info.gain; } + uint8 GetMixMode() const + { return Info.mixMode; } bool IsMasterEffect() const - { return (Info.dwInputRouting & SNDMIXPLUGININFO::irApplyToMaster) != 0; }; + { return (Info.routingFlags & SNDMIXPLUGININFO::irApplyToMaster) != 0; } bool IsWetMix() const - { return (Info.dwInputRouting & SNDMIXPLUGININFO::irWetMix) != 0; }; + { return (Info.routingFlags & SNDMIXPLUGININFO::irWetMix) != 0; } bool IsExpandedMix() const - { return (Info.dwInputRouting & SNDMIXPLUGININFO::irExpandMix) != 0; }; + { return (Info.routingFlags & SNDMIXPLUGININFO::irExpandMix) != 0; } bool IsBypassed() const - { return (Info.dwInputRouting & SNDMIXPLUGININFO::irBypass) != 0; }; + { return (Info.routingFlags & SNDMIXPLUGININFO::irBypass) != 0; } // Input routing setters - void SetGain(int gain) - { Info.dwInputRouting = (Info.dwInputRouting & 0xFF00FFFF) | ((gain & 0xFF) << 16); if(pMixPlugin != nullptr) pMixPlugin->RecalculateGain(); }; - void SetMixMode(int mixMode) - { Info.dwInputRouting = (Info.dwInputRouting & 0xFFFF00FF) | ((mixMode & 0xFF) << 8); }; + void SetGain(uint8 gain) + { Info.gain = gain; if(pMixPlugin != nullptr) pMixPlugin->RecalculateGain(); } + void SetMixMode(uint8 mixMode) + { Info.mixMode = mixMode; } void SetMasterEffect(bool master = true) - { if(master) Info.dwInputRouting |= SNDMIXPLUGININFO::irApplyToMaster; else Info.dwInputRouting &= ~SNDMIXPLUGININFO::irApplyToMaster; }; + { if(master) Info.routingFlags |= SNDMIXPLUGININFO::irApplyToMaster; else Info.routingFlags &= ~SNDMIXPLUGININFO::irApplyToMaster; } void SetWetMix(bool wetMix = true) - { if(wetMix) Info.dwInputRouting |= SNDMIXPLUGININFO::irWetMix; else Info.dwInputRouting &= ~SNDMIXPLUGININFO::irWetMix; }; + { if(wetMix) Info.routingFlags |= SNDMIXPLUGININFO::irWetMix; else Info.routingFlags &= ~SNDMIXPLUGININFO::irWetMix; } void SetExpandedMix(bool expanded = true) - { if(expanded) Info.dwInputRouting |= SNDMIXPLUGININFO::irExpandMix; else Info.dwInputRouting &= ~SNDMIXPLUGININFO::irExpandMix; }; + { if(expanded) Info.routingFlags |= SNDMIXPLUGININFO::irExpandMix; else Info.routingFlags &= ~SNDMIXPLUGININFO::irExpandMix; } void SetBypass(bool bypass = true) - { if(pMixPlugin != nullptr) pMixPlugin->Bypass(bypass); else Info.SetBypass(bypass); }; + { if(pMixPlugin != nullptr) pMixPlugin->Bypass(bypass); else Info.SetBypass(bypass); } // Output routing getters bool IsOutputToMaster() const - { return Info.dwOutputRouting == 0; }; + { return Info.dwOutputRouting == 0; } PLUGINDEX GetOutputPlugin() const - { return Info.dwOutputRouting >= 0x80 ? static_cast<PLUGINDEX>(Info.dwOutputRouting - 0x80) : PLUGINDEX_INVALID; }; + { return Info.dwOutputRouting >= 0x80 ? static_cast<PLUGINDEX>(Info.dwOutputRouting - 0x80) : PLUGINDEX_INVALID; } // Output routing setters void SetOutputToMaster() - { Info.dwOutputRouting = 0; }; + { Info.dwOutputRouting = 0; } void SetOutputPlugin(PLUGINDEX plugin) - { if(plugin < MAX_MIXPLUGINS) Info.dwOutputRouting = plugin + 0x80; else Info.dwOutputRouting = 0; }; + { if(plugin < MAX_MIXPLUGINS) Info.dwOutputRouting = plugin + 0x80; else Info.dwOutputRouting = 0; } }; // rewbs.dryRatio: Hopefully this doesn't need to be a fixed size. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-12 16:10:24
|
Revision: 1522 http://sourceforge.net/p/modplug/code/1522 Author: saga-games Date: 2013-02-12 16:10:16 +0000 (Tue, 12 Feb 2013) Log Message: ----------- [Ref] Tried to unify the multiple lists of supported file formats a bit. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mptrack.cpp trunk/OpenMPT/mptrack/View_tre.cpp trunk/OpenMPT/soundlib/Snd_defs.h trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Tables.cpp trunk/OpenMPT/unlha/UNLHA32.H trunk/OpenMPT/unlha/Unlha.cpp trunk/OpenMPT/unrar/Unrar.cpp trunk/OpenMPT/unrar/Unrar32.h trunk/OpenMPT/unzip/unzip.cpp trunk/OpenMPT/unzip/unzip.h Modified: trunk/OpenMPT/mptrack/Mptrack.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-12 16:10:16 UTC (rev 1522) @@ -1181,12 +1181,16 @@ void CTrackApp::OnFileOpen() //-------------------------- { + std::vector<const char *> modExtensions = CSoundFile::GetSupportedExtensions(true); + std::string exts; + for(size_t i = 0; i < modExtensions.size(); i++) + { + exts += std::string("*.") + modExtensions[i] + std::string(";"); + } + static int nFilterIndex = 0; FileDlgResult files = ShowOpenSaveFileDialog(true, "", "", - "All Modules|*.mod;*.nst;*.wow;*.s3m;*.stm;*.669;*.mtm;*.xm;*.it;*.itp;*.mptm;*.ult;*.mdz;*.s3z;*.xmz;*.itz;mod.*;*.far;*.mdl;*.okt;*.dmf;*.ptm;*.mdr;*.med;*.ams;*.dbm;*.dsm;*.mid;*.rmi;*.smf;*.umx;*.amf;*.psm;*.mt2;*.gdm;*.imf;*.j2b" -#ifndef NO_MO3_SUPPORT - ";*.mo3" -#endif + "All Modules|" + exts + "|" "Compressed Modules (*.mdz;*.s3z;*.xmz;*.itz" #ifndef NO_MO3_SUPPORT Modified: trunk/OpenMPT/mptrack/View_tre.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_tre.cpp 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/mptrack/View_tre.cpp 2013-02-12 16:10:16 UTC (rev 1522) @@ -422,11 +422,11 @@ { _splitpath(lpMidiLib->MidiMap[iPerc|0x80], NULL, NULL, szName, szExt); strncat(s, ": ", sizeof(s)); - s[sizeof(s)-1] = 0; + StringFixer::SetNullTerminator(s); strncat(s, szName, sizeof(s)); - s[sizeof(s)-1] = 0; + StringFixer::SetNullTerminator(s); strncat(s, szExt, sizeof(s)); - s[sizeof(s)-1] = 0; + StringFixer::SetNullTerminator(s); if (szName[0]) dwImage = IMAGE_SAMPLES; } if (!m_tiPerc[iPerc]) @@ -1562,6 +1562,18 @@ } +struct find_str +{ + find_str(const char *str): s1(str) { } + + bool operator() (const char *s2) const + { + return !strcmp(s1, s2); + } + + const char *s1; +}; + // Refresh Instrument Library void CModTree::FillInstrumentLibrary() //------------------------------------ @@ -1649,6 +1661,8 @@ if(strlen(szPath) >= CountOf(szPath) - 1) return; + std::vector<const char *> modExts = CSoundFile::GetSupportedExtensions(false); + // Enumerating Directories and samples/instruments if (szPath[strlen(szPath) - 1] != '\\') strcat(szPath, "\\"); @@ -1691,55 +1705,29 @@ strcpy(szFileName, m_szInstrLibPath); strncat(szFileName, wfd.cFileName, sizeof(szFileName)); _splitpath(szFileName, NULL, NULL, NULL, s); - // Instruments - if ((!lstrcmpi(s, ".xi")) - || (!lstrcmpi(s, ".iti")) - || (!lstrcmpi(s, ".pat")) ) + + if(s[0]) { + const size_t len = strlen(s); + for(size_t i = 0; i < len; i++) + { + s[i] = tolower(s[i + 1]); + } + } + + // Instruments + if ((!strcmp(s, "xi")) + || (!strcmp(s, "iti")) + || (!strcmp(s, "pat")) ) + { if (!m_pDataTree) { ModTreeBuildTVIParam(tvis, wfd.cFileName, IMAGE_INSTRUMENTS); InsertItem(&tvis); } - } else - // Songs - if(!lstrcmpi(s, ".mod") - || !lstrcmpi(s, ".s3m") - || !lstrcmpi(s, ".xm") - || !lstrcmpi(s, ".it") - || !lstrcmpi(s, ".mptm") - || !lstrcmpi(s, ".itp") - || !lstrcmpi(s, ".mdz") - || !lstrcmpi(s, ".s3z") - || !lstrcmpi(s, ".xmz") - || !lstrcmpi(s, ".itz") - || !lstrcmpi(s, ".669") - || !lstrcmpi(s, ".ams") - || !lstrcmpi(s, ".amf") - || !lstrcmpi(s, ".mdz") - || !lstrcmpi(s, ".dsm") - || !lstrcmpi(s, ".far") - || !lstrcmpi(s, ".mdl") - || !lstrcmpi(s, ".mtm") - || !lstrcmpi(s, ".nst") - || !lstrcmpi(s, ".okt") - || !lstrcmpi(s, ".stm") - || !lstrcmpi(s, ".ult") - || !lstrcmpi(s, ".psm") - || !lstrcmpi(s, ".dmf") - || !lstrcmpi(s, ".mt2") - || !lstrcmpi(s, ".med") - || !lstrcmpi(s, ".wow") - || !lstrcmpi(s, ".gdm") - || !lstrcmpi(s, ".imf") - || !lstrcmpi(s, ".j2b") - || !lstrcmpi(s, ".umx") - || !lstrcmpi(s, ".uax") -#ifndef NO_MO3_SUPPORT - || !lstrcmpi(s, ".mo3") -#endif // NO_MO3_SUPPORT - ) + } else if(std::find_if(modExts.begin(), modExts.end(), find_str(s)) != modExts.end()) { + // Songs if (m_pDataTree) { ModTreeBuildTVIParam(tvis, wfd.cFileName, IMAGE_FOLDERSONG); @@ -1747,34 +1735,34 @@ } } else // Samples - if(!lstrcmpi(s, ".wav") - || !lstrcmpi(s, ".flac") - || !lstrcmpi(s, ".smp") - || !lstrcmpi(s, ".raw") - || !lstrcmpi(s, ".s3i") - || !lstrcmpi(s, ".its") - || !lstrcmpi(s, ".aif") - || !lstrcmpi(s, ".aiff") - || !lstrcmpi(s, ".snd") - || !lstrcmpi(s, ".svx") - || !lstrcmpi(s, ".voc") - || !lstrcmpi(s, ".8sv") - || !lstrcmpi(s, ".8svx") - || !lstrcmpi(s, ".16sv") - || !lstrcmpi(s, ".16svx") + if(!strcmp(s, "wav") + || !strcmp(s, "flac") + || !strcmp(s, "smp") + || !strcmp(s, "raw") + || !strcmp(s, "s3i") + || !strcmp(s, "its") + || !strcmp(s, "aif") + || !strcmp(s, "aiff") + || !strcmp(s, "snd") + || !strcmp(s, "svx") + || !strcmp(s, "voc") + || !strcmp(s, "8sv") + || !strcmp(s, "8svx") + || !strcmp(s, "16sv") + || !strcmp(s, "16svx") || (m_bShowAllFiles // Exclude the extensions below - && lstrcmpi(s, ".txt") - && lstrcmpi(s, ".diz") - && lstrcmpi(s, ".nfo") - && lstrcmpi(s, ".doc") - && lstrcmpi(s, ".ini") - && lstrcmpi(s, ".pdf") - && lstrcmpi(s, ".zip") - && lstrcmpi(s, ".rar") - && lstrcmpi(s, ".lha") - && lstrcmpi(s, ".exe") - && lstrcmpi(s, ".dll") - && lstrcmpi(s, ".mol")) + && strcmp(s, "txt") + && strcmp(s, "diz") + && strcmp(s, "nfo") + && strcmp(s, "doc") + && strcmp(s, "ini") + && strcmp(s, "pdf") + && strcmp(s, "zip") + && strcmp(s, "rar") + && strcmp(s, "lha") + && strcmp(s, "exe") + && strcmp(s, "dll") + && strcmp(s, "mol")) ) { if (!m_pDataTree) Modified: trunk/OpenMPT/soundlib/Snd_defs.h =================================================================== --- trunk/OpenMPT/soundlib/Snd_defs.h 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/soundlib/Snd_defs.h 2013-02-12 16:10:16 UTC (rev 1522) @@ -102,7 +102,10 @@ MOD_TYPE_MPT = 0x1000000, MOD_TYPE_IMF = 0x2000000, MOD_TYPE_AMS2 = 0x4000000, - MOD_TYPE_UMX = 0x80000000, // Fake type + // Container formats (not used at the moment) + MOD_TYPE_MO3 = 0x20000000, + MOD_TYPE_GDM = 0x40000000, + MOD_TYPE_UMX = 0x80000000, }; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-12 16:10:16 UTC (rev 1522) @@ -29,11 +29,6 @@ #define UNLHA_SUPPORT #define UNGZIP_SUPPORT #define ZIPPED_MOD_SUPPORT -LPCSTR glpszModExtensions = "mod|s3m|xm|it|itp|mptm|stm|nst|ult|669|wow|mtm|med|far|mdl|ams|dsm|amf|okt|dmf|ptm|psm|mt2|umx|uax|gdm|imf|j2b" -#ifndef NO_UNMO3_SUPPORT -"|mo3" -#endif -; #endif // NO_ARCHIVE_SUPPORT #else // NO_COPYRIGHT: EarSaver only loads mod/s3m/xm/it/wav #define MODPLUG_BASIC_SUPPORT @@ -548,8 +543,10 @@ { FileReader file(reinterpret_cast<const char*>(lpStream), dwMemLength); + const std::vector<const char *> modExtensions = GetSupportedExtensions(true); + #ifdef ZIPPED_MOD_SUPPORT - CZipArchive unzip(file, glpszModExtensions); + CZipArchive unzip(file, modExtensions); if(unzip.IsArchive() && unzip.ExtractFile()) { file = unzip.GetOutputFile(); @@ -558,7 +555,7 @@ } #endif #ifdef UNRAR_SUPPORT - CRarArchive unrar((LPBYTE)lpStream, dwMemLength, glpszModExtensions); + CRarArchive unrar((LPBYTE)lpStream, dwMemLength); if(unrar.IsArchive()) { if(unrar.ExtrFile() && unrar.GetOutputFile()) @@ -570,7 +567,7 @@ } #endif #ifdef UNLHA_SUPPORT - CLhaArchive unlha((LPBYTE)lpStream, dwMemLength, glpszModExtensions); + CLhaArchive unlha((LPBYTE)lpStream, dwMemLength); if(unlha.IsArchive()) { if(unlha.ExtractFile() && unlha.GetOutputFile()) Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-12 16:10:16 UTC (rev 1522) @@ -420,6 +420,8 @@ bool ReadJ2B(FileReader &file); bool ReadMID(const LPCBYTE lpStream, DWORD dwMemLength); + static std::vector<const char *> GetSupportedExtensions(bool otherFormats); + void UpgradeModFlags(); void UpgradeSong(); @@ -779,18 +781,6 @@ int _muldiv(long a, long b, long c); int _muldivr(long a, long b, long c); -/////////////////////////////////////////////////////////// -// File Formats Information (name, extension, etc) - -struct MODFORMATINFO -{ - MODTYPE mtFormatId; // MOD_TYPE_XXXX - LPCSTR lpszFormatName; // "ProTracker" - LPCSTR lpszExtension; // ".xxx" - DWORD dwPadding; -}; - - // Read instrument property with 'code' and 'size' from 'file' to instrument 'pIns'. void ReadInstrumentExtensionField(ModInstrument* pIns, const uint32 code, const uint16 size, FileReader &file); Modified: trunk/OpenMPT/soundlib/Tables.cpp =================================================================== --- trunk/OpenMPT/soundlib/Tables.cpp 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/soundlib/Tables.cpp 2013-02-12 16:10:16 UTC (rev 1522) @@ -18,39 +18,100 @@ // end rewbs.resamplerConf -/////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////// +// File Formats Information (name, extension, etc) -/*MODFORMATINFO gModFormatInfo[] = +struct ModFormatInfo { - { MOD_TYPE_MOD, "ProTracker", ".mod", 0 }, - { MOD_TYPE_S3M, "ScreamTracker III", ".s3m", 0 }, - { MOD_TYPE_XM, "FastTracker II", ".xm", 0 }, - { MOD_TYPE_IT, "Impulse Tracker", ".it", 0 }, - { MOD_TYPE_MDL, "DigiTracker", ".mdl", 0 }, - { MOD_TYPE_MTM, "MultiTracker", ".mtm", 0 }, - { MOD_TYPE_STM, "ScreamTracker II", ".stm", 0 }, - { MOD_TYPE_OKT, "Oktalyzer", ".okt", 0 }, - { MOD_TYPE_MED, "OctaMed", ".med", 0 }, - { MOD_TYPE_669, "UNIS 669", ".669", 0 }, - { MOD_TYPE_FAR, "Farandole Composer", ".far", 0 }, - { MOD_TYPE_ULT, "UltraTracker", ".ult", 0 }, - { MOD_TYPE_PTM, "PolyTracker", ".ptm", 0 }, - { MOD_TYPE_WAV, "Wave", ".wav", 0 }, - { MOD_TYPE_MID, "Midi", ".mid", 0 }, - { MOD_TYPE_AMS, "Extreme's Tracker", ".ams", 0 }, - { MOD_TYPE_AMS2, "Velvet Studio", ".ams", 0 }, - { MOD_TYPE_AMF|MOD_TYPE_AMF0,"Asylum / DSMI", ".amf", 0 }, - { MOD_TYPE_DSM, "DSIK Format", ".dsm", 0 }, - { MOD_TYPE_DMF, "X-Tracker", ".dmf", 0 }, - { MOD_TYPE_DBM, "DigiBooster Pro", ".dbm", 0 }, - { MOD_TYPE_PSM, "Epic Megagames MASI", ".psm", 0 }, - { MOD_TYPE_UMX, "Unreal Music", ".umx", 0 }, - { MOD_TYPE_MT2, "MadTracker 2", ".mt2", 0 }, - { MOD_TYPE_MPT, "OpenMPT", ".mptm", 0 }, - { MOD_TYPE_J2B, "Galaxy Sound System", ".j2b", 0 }, - { MOD_TYPE_IMF, "Imago Orpheus", ".imf", 0 }, -};*/ + MODTYPE format; // MOD_TYPE_XXXX + char *name; // "ProTracker" + char *extension; // "mod" +}; +const ModFormatInfo modFormatInfo[] = +{ + { MOD_TYPE_MOD, "ProTracker", "mod" }, + { MOD_TYPE_S3M, "ScreamTracker III", "s3m" }, + { MOD_TYPE_XM, "FastTracker II", "xm" }, + { MOD_TYPE_IT, "Impulse Tracker", "it" }, + { MOD_TYPE_IT, "Impulse Tracker Project", "itp" }, + { MOD_TYPE_MPT, "OpenMPT", "mptm" }, + { MOD_TYPE_STM, "ScreamTracker II", "stm" }, + { MOD_TYPE_MOD, "NoiseTracker", "nst" }, + { MOD_TYPE_MOD, "Soundtracker", "m15" }, + { MOD_TYPE_MOD, "Soundtracker", "stk" }, + { MOD_TYPE_MOD, "Mod's Grave", "wow" }, + { MOD_TYPE_ULT, "UltraTracker", "ult" }, + { MOD_TYPE_669, "Composer 669 / UNIS 669", "669" }, + { MOD_TYPE_MTM, "MultiTracker", "mtm" }, + { MOD_TYPE_MED, "OctaMed", "med" }, + { MOD_TYPE_FAR, "Farandole Composer", "far" }, + { MOD_TYPE_MDL, "DigiTracker", "mdl" }, + { MOD_TYPE_AMS, "Extreme's Tracker", "ams" }, + { MOD_TYPE_AMS2, "Velvet Studio", "ams" }, + { MOD_TYPE_DSM, "DSIK Format", "dsm" }, + { MOD_TYPE_AMF, "DSMI", "amf" }, + { MOD_TYPE_AMF0, "ASYLUM", "amf" }, + { MOD_TYPE_OKT, "Oktalyzer", "okt" }, + { MOD_TYPE_DMF, "X-Tracker", "dmf" }, + { MOD_TYPE_PTM, "PolyTracker", "ptm" }, + { MOD_TYPE_PSM, "Epic Megagames MASI", "psm" }, + { MOD_TYPE_MT2, "MadTracker 2", "mt2" }, + { MOD_TYPE_DBM, "DigiBooster Pro", "dbm" }, + { MOD_TYPE_IMF, "Imago Orpheus", "imf" }, + { MOD_TYPE_J2B, "Galaxy Sound System", "j2b" }, + + // Container formats + { MOD_TYPE_GDM, "General Digital Music", "gdm" }, + { MOD_TYPE_UMX, "Unreal Music", "umx" }, + { MOD_TYPE_UMX, "Unreal Sounds", "uax" }, +#ifndef NO_MO3 + { MOD_TYPE_MO3, "MO3", "mo3" }, +#endif // NO_MO3 + + // Compressed modules + { MOD_TYPE_MOD, "ProTracker", "mdz" }, + { MOD_TYPE_MOD, "ProTracker", "mdr" }, + { MOD_TYPE_S3M, "ScreamTracker III", "s3z" }, + { MOD_TYPE_XM, "FastTracker II", "xmz" }, + { MOD_TYPE_IT, "Impulse Tracker", "itz" }, + { MOD_TYPE_MPT, "OpenMPT", "mptmz" }, +}; + +const ModFormatInfo otherFormatInfo[] = +{ + // Other stuff + { MOD_TYPE_WAV, "Wave", "wav" }, + { MOD_TYPE_MID, "MIDI", "mid" }, + { MOD_TYPE_MID, "MIDI", "rmi" }, + { MOD_TYPE_MID, "MIDI", "smf" }, +}; + + +std::vector<const char *> CSoundFile::GetSupportedExtensions(bool otherFormats) +//----------------------------------------------------------------------------- +{ + std::vector<const char *> exts; + exts.reserve(CountOf(modFormatInfo) + otherFormats ? CountOf(otherFormatInfo) : 0); + for(size_t i = 0; i < CountOf(modFormatInfo); i++) + { + // Avoid dupes in list + if(i == 0 || strcmp(modFormatInfo[i].extension, modFormatInfo[i - 1].extension)) + { + exts.push_back(modFormatInfo[i].extension); + } + } + if(otherFormats) + { + for(size_t i = 0; i < CountOf(otherFormatInfo); i++) + { + exts.push_back(otherFormatInfo[i].extension); + } + } + return exts; +} + + /////////////////////////////////////////////////////////////////////// #pragma data_seg(".tables") #pragma bss_seg(".modplug") Modified: trunk/OpenMPT/unlha/UNLHA32.H =================================================================== --- trunk/OpenMPT/unlha/UNLHA32.H 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/unlha/UNLHA32.H 2013-02-12 16:10:16 UTC (rev 1522) @@ -41,7 +41,7 @@ enum { NC = 255 + MAXMATCH + 2 - THRESHOLD }; public: - CLhaArchive(LPBYTE lpStream, DWORD dwMemLength, LPCSTR lpszExtensions=NULL); + CLhaArchive(LPBYTE lpStream, DWORD dwMemLength); ~CLhaArchive(); public: Modified: trunk/OpenMPT/unlha/Unlha.cpp =================================================================== --- trunk/OpenMPT/unlha/Unlha.cpp 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/unlha/Unlha.cpp 2013-02-12 16:10:16 UTC (rev 1522) @@ -58,8 +58,8 @@ #include "shuf.cpp" #include "larc.cpp" -CLhaArchive::CLhaArchive(LPBYTE lpStream, DWORD dwMemLength, LPCSTR lpszExtensions) -//--------------------------------------------------------------------------------- +CLhaArchive::CLhaArchive(LPBYTE lpStream, DWORD dwMemLength) +//---------------------------------------------------------- { // File Read m_lpStream = lpStream; Modified: trunk/OpenMPT/unrar/Unrar.cpp =================================================================== --- trunk/OpenMPT/unrar/Unrar.cpp 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/unrar/Unrar.cpp 2013-02-12 16:10:16 UTC (rev 1522) @@ -58,8 +58,8 @@ -CRarArchive::CRarArchive(LPBYTE lpStream, DWORD dwMemLength, LPCSTR lpszExtensions) -//--------------------------------------------------------------------------------- +CRarArchive::CRarArchive(LPBYTE lpStream, DWORD dwMemLength) +//---------------------------------------------------------- { // File Read m_lpStream = lpStream; Modified: trunk/OpenMPT/unrar/Unrar32.h =================================================================== --- trunk/OpenMPT/unrar/Unrar32.h 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/unrar/Unrar32.h 2013-02-12 16:10:16 UTC (rev 1522) @@ -7,7 +7,7 @@ //=============== { public: - CRarArchive(LPBYTE lpStream, DWORD dwMemLength, LPCSTR lpszExtensions=NULL); + CRarArchive(LPBYTE lpStream, DWORD dwMemLength); ~CRarArchive(); public: Modified: trunk/OpenMPT/unzip/unzip.cpp =================================================================== --- trunk/OpenMPT/unzip/unzip.cpp 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/unzip/unzip.cpp 2013-02-12 16:10:16 UTC (rev 1522) @@ -8,8 +8,10 @@ */ #include "../soundlib/FileReader.h" +#include <vector> #include "unzip.h" #include "../common/misc_util.h" +#include <algorithm> #ifndef ZLIB_WINAPI #define ZLIB_WINAPI @@ -88,8 +90,8 @@ }; -CZipArchive::CZipArchive(FileReader &file, const char *ext) : inFile(file), extensions(ext) -//----------------------------------------------------------------------------------------- +CZipArchive::CZipArchive(FileReader &file, const std::vector<const char *> &ext) : inFile(file), extensions(ext) +//-------------------------------------------------------------------------------------------------------------- { zlib_filefunc_def functions = { @@ -121,6 +123,19 @@ } +struct find_str +{ + find_str(const char *str): s1(str) { } + + bool operator() (const char *s2) const + { + return !strcmp(s1, s2); + } + + const char *s1; +}; + + bool CZipArchive::ExtractFile() //----------------------------- { @@ -140,7 +155,9 @@ char *ext = name + info.size_filename; while(ext > name) { - if(*(--ext) == '.') + ext--; + *ext = tolower(*ext); + if(*ext == '.') { ext++; break; @@ -148,37 +165,16 @@ } // Compare with list of preferred extensions - char extCmp[16]; - size_t i = 0, j = 0; - bool foundPreferred = false; - while(extensions[i]) + if(std::find_if(extensions.begin(), extensions.end(), find_str(ext)) != extensions.end()) { - char c = extensions[i++]; - extCmp[j] = c; - if(c == '|') - { - extCmp[j] = 0; - j = 0; - if(!lstrcmpi(ext, extCmp)) - { - // File has a preferred extension: use it. - unzGetFilePos(zipFile, &bestFile); - foundPreferred = true; - break; - } - } else - { - j++; - } - } - if(foundPreferred) - { + // File has a preferred extension: use it. + unzGetFilePos(zipFile, &bestFile); break; } - if(lstrcmpi(ext, "diz") - && lstrcmpi(ext, "nfo") - && lstrcmpi(ext, "txt") + if(strcmp(ext, "diz") + && strcmp(ext, "nfo") + && strcmp(ext, "txt") && info.uncompressed_size >= biggestFile) { // If this isn't some kind of info file, we should maybe pick it. Modified: trunk/OpenMPT/unzip/unzip.h =================================================================== --- trunk/OpenMPT/unzip/unzip.h 2013-02-11 22:35:29 UTC (rev 1521) +++ trunk/OpenMPT/unzip/unzip.h 2013-02-12 16:10:16 UTC (rev 1522) @@ -16,7 +16,7 @@ protected: FileReader inFile, outFile; void *zipFile; - const char *extensions; + const std::vector<const char *> &extensions; public: @@ -25,6 +25,6 @@ bool ExtractFile(); void *GetComments(bool get); - CZipArchive(FileReader &file, const char *ext); + CZipArchive(FileReader &file, const std::vector<const char *> &ext); ~CZipArchive(); }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-13 00:22:09
|
Revision: 1523 http://sourceforge.net/p/modplug/code/1523 Author: saga-games Date: 2013-02-13 00:21:57 +0000 (Wed, 13 Feb 2013) Log Message: ----------- [New] Can now import MPEG samples using mpg123 (tx coda) Modified Paths: -------------- trunk/OpenMPT/common/stdafx.h trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/View_tre.cpp trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/common/stdafx.h =================================================================== --- trunk/OpenMPT/common/stdafx.h 2013-02-12 16:10:16 UTC (rev 1522) +++ trunk/OpenMPT/common/stdafx.h 2013-02-13 00:21:57 UTC (rev 1523) @@ -91,7 +91,13 @@ // Define to build without DirectSound support. //#define NO_DSOUND +// Define to build without FLAC support +//#define NO_FLAC +// Define to build without MP3 import support (via mpg123) +//#define NO_MP3_SAMPLES + + void Log(LPCSTR format,...); #include "../common/typedefs.h" Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-02-12 16:10:16 UTC (rev 1522) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-02-13 00:21:57 UTC (rev 1523) @@ -991,9 +991,14 @@ static int nLastIndex = 0; FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(true, "", "", - "All Samples|*.wav;*.flac;*.pat;*.s3i;*.smp;*.snd;*.raw;*.xi;*.aif;*.aiff;*.its;*.8sv;*.8svx;*.svx;*.pcm|" + "All Samples|*.wav;*.flac;*.pat;*.s3i;*.smp;*.snd;*.raw;*.xi;*.aif;*.aiff;*.its;*.8sv;*.8svx;*.svx;*.pcm;*.mp1;*.mp2;*.mp3|" "Wave Files (*.wav)|*.wav|" +#ifndef NO_FLAC "FLAC Files (*.flac)|*.flac|" +#endif // NO_FLAC +#ifndef NO_MP3_SAMPLES + "MPEG Files (*.mp1,*.mp2,*.mp3)|*.mp1;*.mp2;*.mp3|" +#endif // NO_MP3_SAMPLES "XI Samples (*.xi)|*.xi|" "Impulse Tracker Samples (*.its)|*.its|" "ScreamTracker Samples (*.s3i,*.smp)|*.s3i;*.smp|" Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2013-02-12 16:10:16 UTC (rev 1522) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2013-02-13 00:21:57 UTC (rev 1523) @@ -1534,6 +1534,11 @@ if (p) { bOk = m_WaveFile.ReadInstrumentFromFile(1, p, dwLen); + if(!bOk) + { + bOk = m_WaveFile.ReadSampleFromFile(1, p, dwLen); + m_WaveFile.AllocateInstrument(1, 1); + } f.Unlock(); } if (bOk) Modified: trunk/OpenMPT/mptrack/View_tre.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_tre.cpp 2013-02-12 16:10:16 UTC (rev 1522) +++ trunk/OpenMPT/mptrack/View_tre.cpp 2013-02-13 00:21:57 UTC (rev 1523) @@ -1522,11 +1522,16 @@ //--------------------------------------------- { FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(true, "", "", - "All Instruments and Banks|*.xi;*.pat;*.iti;*.wav;*.aif;*.aiff;*.sf2;*.sbk;*.dls;*.flac|" + "All Instruments and Banks|*.xi;*.pat;*.iti;*.wav;*.aif;*.aiff;*.sf2;*.sbk;*.dls;*.flac;*.mp1;*.mp2;*.mp3|" "FastTracker II Instruments (*.xi)|*.xi|" "GF1 Patches (*.pat)|*.pat|" "Wave Files (*.wav)|*.wav|" +#ifndef NO_FLAC "FLAC Files (*.flac)|*.flac|" +#endif // NO_FLAC +#ifndef NO_MP3_SAMPLES + "MPEG Files (*.mp1,*.mp2,*.mp3)|*.mp1;*.mp2;*.mp3|" +#endif // NO_MP3_SAMPLES "Impulse Tracker Instruments (*.iti)|*.iti;*.its|" "SoundFont 2.0 Banks (*.sf2)|*.sf2;*.sbk|" "DLS Sound Banks (*.dls)|*.dls|" @@ -1737,6 +1742,9 @@ // Samples if(!strcmp(s, "wav") || !strcmp(s, "flac") + || !strcmp(s, "mp1") + || !strcmp(s, "mp2") + || !strcmp(s, "mp3") || !strcmp(s, "smp") || !strcmp(s, "raw") || !strcmp(s, "s3i") Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-12 16:10:16 UTC (rev 1522) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-13 00:21:57 UTC (rev 1523) @@ -38,7 +38,8 @@ && !ReadPATSample(nSample, lpMemFile, dwFileLength) && !Read8SVXSample(nSample, lpMemFile, dwFileLength) && !ReadS3ISample(nSample, lpMemFile, dwFileLength) - && !ReadFLACSample(nSample, file)) + && !ReadFLACSample(nSample, file) + && !ReadMP3Sample(nSample, file)) { return false; } @@ -73,8 +74,13 @@ || (psig[0] == BigEndian(0x464F524D) && psig[2] == LittleEndian(0x43464941)) // AIFF-C signature || (psig[0] == BigEndian(0x464F524D) && psig[2] == LittleEndian(0x58565338)) // 8SVX signature || psig[0] == LittleEndian(ITSample::magic) // ITS signature +#ifndef NO_FLAC || psig[0] == LittleEndian('CaLf') // FLAC signature - || psig[0] == LittleEndian('SggO') // OGG signature (for FLAC in OGG) +#endif // NO_FLAC +#ifndef NO_MP3_SAMPLES + || (lpMemFile[0] == 0xFF && lpMemFile[1] == 0xFB) // MP3 signature + || (lpMemFile[0] == 'I' && lpMemFile[1] == 'D' && lpMemFile[2] == '3') // MP3 signature +#endif // NO_MP3_SAMPLES ) { // Scanning free sample @@ -2210,4 +2216,130 @@ #else return false; #endif // NO_FLAC -} \ No newline at end of file +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// MP3 Samples + +#ifndef NO_MP3_SAMPLES + +namespace mpg123 +{ + typedef struct {int foo;} mpg123_handle; + typedef int (*pfn_init )(); + typedef mpg123_handle* (*pfn_new )(char*,int*); + typedef void (*pfn_delete )(mpg123_handle*); + typedef int (*pfn_open_handle )(mpg123_handle*, void*); + typedef int (*pfn_replace_reader_handle)(mpg123_handle*, + size_t(*)(void *, void *, size_t), + off_t(*)(void *, off_t, int), + void(*)(void *)); + typedef int (*pfn_read )(mpg123_handle*, unsigned char*, size_t, size_t*); + typedef int (*pfn_getformat )(mpg123_handle*, long*, int*, int*); + typedef int (*pfn_scan )(mpg123_handle*); + typedef off_t (*pfn_length )(mpg123_handle*); + + size_t FileReaderRead(void *fp, void *buf, size_t count) + { + FileReader &file = *static_cast<FileReader *>(fp); + size_t readBytes = Util::Min(count, static_cast<size_t>(file.BytesLeft())); + memcpy(buf, file.GetRawData(), readBytes); + file.Skip(readBytes); + return readBytes; + } + + off_t FileReaderLSeek(void *fp, off_t offset, int whence) + { + FileReader &file = *static_cast<FileReader *>(fp); + if(whence == SEEK_CUR) file.Seek(file.GetPosition() + offset); + else if(whence == SEEK_END) file.Seek(file.GetLength() + offset); + else file.Seek(offset); + return file.GetPosition(); + } + + enum mpg123_enc_enum + { + MPG123_ENC_16 = 0x040, MPG123_ENC_SIGNED = 0x080, + }; +}; + +#endif // NO_MP3_SAMPLES + + +bool CSoundFile::ReadMP3Sample(SAMPLEINDEX sample, FileReader &file) +//------------------------------------------------------------------ +{ +#ifndef NO_MP3_SAMPLES + HMODULE mp3lib = nullptr; + + if(!mp3lib) + { +#ifdef MODPLUG_TRACKER + const CString path = CString(theApp.GetAppDirPath()) + "libmpg123-0.dll"; + mp3lib = LoadLibrary(path); +#else + mp3lib = LoadLibrary(_TEXT("libmpg123-0.dll")); +#endif // MODPLUG_TRACKER + } + if(!mp3lib) return false; + + #define MP3_DYNAMICBIND(f) mpg123::pfn_ ## f mpg123_ ## f = (mpg123::pfn_ ## f)GetProcAddress(mp3lib, "mpg123_" #f); if(!mpg123_ ## f) return false + + MP3_DYNAMICBIND(init); + MP3_DYNAMICBIND(new); + MP3_DYNAMICBIND(delete); + MP3_DYNAMICBIND(open_handle); + MP3_DYNAMICBIND(replace_reader_handle); + MP3_DYNAMICBIND(read); + MP3_DYNAMICBIND(getformat); + MP3_DYNAMICBIND(scan); + MP3_DYNAMICBIND(length); + + #undef MP3_DYNAMICBIND + + if(mpg123_init()) return false; + + mpg123::mpg123_handle *mh; + int err; + if((mh = mpg123_new(0, &err)) == nullptr) return false; + file.Rewind(); + + long rate; int nchannels, encoding; + SmpLength length; + + // Set up decoder... + if(mpg123_replace_reader_handle(mh, mpg123::FileReaderRead, mpg123::FileReaderLSeek, 0) + || mpg123_open_handle(mh, &file) + || mpg123_scan(mh) + || mpg123_getformat(mh, &rate, &nchannels, &encoding) + || !nchannels || nchannels > 2 + || (encoding & mpg123::MPG123_ENC_16 | mpg123::MPG123_ENC_SIGNED) == 0 + || (length = mpg123_length(mh)) == 0) + { + mpg123_delete(mh); + return false; + } + + CriticalSection cs; + DestroySample(sample); + Samples[sample].Initialize(); + Samples[sample].nLength = length; + + Samples[sample].nC5Speed = rate; + Samples[sample].uFlags.set(CHN_16BIT); + Samples[sample].uFlags.set(CHN_STEREO, nchannels == 2); + Samples[sample].AllocateSample(); + + size_t ndecoded; + mpg123_read(mh, reinterpret_cast<unsigned char*>(Samples[sample].pSample), Samples[sample].GetSampleSizeInBytes(), &ndecoded); + mpg123_delete(mh); + + if(Samples[sample].pSample != nullptr) + { + Samples[sample].Convert(MOD_TYPE_IT, GetType()); + return true; + } +#endif // NO_MP3_SAMPLES + return false; +} Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-12 16:10:16 UTC (rev 1522) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-13 00:21:57 UTC (rev 1523) @@ -635,6 +635,7 @@ bool ReadITISample(SAMPLEINDEX nSample, FileReader &file); bool Read8SVXSample(SAMPLEINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); bool ReadFLACSample(SAMPLEINDEX sample, FileReader &file); + bool ReadMP3Sample(SAMPLEINDEX sample, FileReader &file); bool SaveWAVSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const; bool SaveRAWSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const; bool SaveFLACSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-13 15:19:53
|
Revision: 1525 http://sourceforge.net/p/modplug/code/1525 Author: saga-games Date: 2013-02-13 15:19:42 +0000 (Wed, 13 Feb 2013) Log Message: ----------- [Imp] Improved sample slot allocation behaviour when reading samples as instruments. [Mod] Several smaller changes in sample loaders (e.g. removed some critical sections and shortened some others). Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2013-02-13 00:33:57 UTC (rev 1524) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2013-02-13 15:19:42 UTC (rev 1525) @@ -1454,8 +1454,6 @@ bOk = FALSE; if (lpFile) { - CriticalSection cs; - if (!m_pSndFile->GetNumInstruments()) { bFirst = TRUE; Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-02-13 00:33:57 UTC (rev 1524) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-02-13 15:19:42 UTC (rev 1525) @@ -765,7 +765,6 @@ if (!lpFile) goto OpenError; { - CriticalSection cs; m_pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_replace); bOk = m_pSndFile->ReadSampleFromFile(m_nSample, lpFile, len); } @@ -786,9 +785,7 @@ BeginWaitCursor(); ModSample &sample = m_pSndFile->GetSample(m_nSample); - CriticalSection cs; - - m_pSndFile->DestroySample(m_nSample); + m_pSndFile->DestroySampleThreadsafe(m_nSample); sample.nLength = len; SampleIO sampleIO( @@ -887,10 +884,7 @@ BeginWaitCursor(); - CriticalSection cs; - m_pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_replace); - m_pSndFile->DestroySample(m_nSample); m_pSndFile->ReadSampleFromSong(m_nSample, pSndFile, nSample); ModSample &sample = m_pSndFile->GetSample(m_nSample); if ((m_pSndFile->GetType() & MOD_TYPE_XM) && (!(sample.uFlags & CHN_PANNING))) @@ -899,7 +893,6 @@ sample.uFlags |= CHN_PANNING; } - cs.Leave(); EndWaitCursor(); m_pModDoc->UpdateAllViews(NULL, (m_nSample << HINT_SHIFT_SMP) | HINT_SAMPLEDATA | HINT_SAMPLEINFO | HINT_SMPNAMES, NULL); Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2013-02-13 00:33:57 UTC (rev 1524) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2013-02-13 15:19:42 UTC (rev 1525) @@ -1795,9 +1795,7 @@ if (Reporting::Confirm("Remove this sample?", "Remove Sample", true) != cnfYes) return; pModDoc->GetSampleUndo().PrepareUndo(m_nSample, sundo_replace); - CriticalSection cs; - pSndFile->DestroySample(m_nSample); - cs.Leave(); + pSndFile->DestroySampleThreadsafe(m_nSample); dwUpdateFlags |= HINT_SMPNAMES; } else @@ -1988,15 +1986,10 @@ CSoundFile *pSndFile = pModDoc->GetSoundFile(); DWORD dwMemSize = GlobalSize(hCpy); - CriticalSection cs; - ModSample &sample = pSndFile->GetSample(m_nSample); memcpy(s, pSndFile->m_szNames[m_nSample], 32); memcpy(s2, sample.filename, 22); - pSndFile->DestroySample(m_nSample); - sample.nLength = 0; - sample.pSample = 0; pSndFile->ReadSampleFromFile(m_nSample, p, dwMemSize); if (!pSndFile->m_szNames[m_nSample][0]) { @@ -2007,8 +2000,6 @@ memcpy(sample.filename, s2, 22); } - cs.Leave(); - GlobalUnlock(hCpy); SetCurSel(0, 0); pModDoc->AdjustEndOfSample(m_nSample); Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-13 00:33:57 UTC (rev 1524) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-13 15:19:42 UTC (rev 1525) @@ -43,6 +43,11 @@ { return false; } + + if(nSample > GetNumSamples()) + { + m_nSamples = nSample; + } return true; } @@ -57,7 +62,8 @@ && (!ReadITIInstrument(nInstr, file)) // Generic read && (!ReadSampleAsInstrument(nInstr, lpMemFile, dwFileLength))) return false; - if (nInstr > m_nInstruments) m_nInstruments = nInstr; + + if(nInstr > GetNumInstruments()) m_nInstruments = nInstr; return true; } @@ -106,16 +112,6 @@ Instruments[nInstr] = pIns; ReadSampleFromFile(nSample, lpMemFile, dwFileLength); - - if(nSample > GetNumSamples()) - { - m_nSamples = nSample; - } - if(nInstr > GetNumInstruments()) - { - m_nInstruments = nInstr; - } - return true; } return false; @@ -285,8 +281,7 @@ return false; } - CriticalSection cs; - DestroySample(targetSample); + DestroySampleThreadsafe(targetSample); const ModSample &sourceSmp = pSrcSong->GetSample(sourceSample); @@ -330,8 +325,7 @@ return false; } - CriticalSection cs; - DestroySample(nSample); + DestroySampleThreadsafe(nSample); strcpy(m_szNames[nSample], ""); ModSample &sample = Samples[nSample]; sample.Initialize(); @@ -726,9 +720,8 @@ || (phdr->version[3] != 0) || (phdr->id[9] != 0) || (phdr->instrum < 1) || (!phdr->samples) || (!pinshdr->layers)) return false; - CriticalSection cs; - DestroySample(nSample); - PatchToSample(this, nSample, lpStream+dwMemPos, dwMemLength-dwMemPos); + DestroySampleThreadsafe(nSample); + PatchToSample(this, nSample, lpStream + dwMemPos, dwMemLength - dwMemPos); if (pinshdr->name[0] > ' ') { memcpy(m_szNames[nSample], pinshdr->name, 16); @@ -890,8 +883,7 @@ || (pss->id != 0x01) || (((DWORD)pss->offset << 4) >= dwFileLength) || (pss->scrs != 0x53524353)) return false; - CriticalSection cs; - DestroySample(nSample); + DestroySampleThreadsafe(nSample); dwMemPos = pss->offset << 4; sample.Initialize(); @@ -1124,8 +1116,7 @@ // Gotta skip 'em all! file.Skip(sizeof(XMSample) * (fileHeader.numSamples - 1)); - CriticalSection cs; - DestroySample(nSample); + DestroySampleThreadsafe(nSample); ModSample &mptSample = Samples[nSample]; sampleHeader.ConvertToMPT(mptSample); @@ -1391,9 +1382,8 @@ soundChunk.Skip(sampleHeader.offset); - CriticalSection cs; ModSample &mptSample = Samples[nSample]; - DestroySample(nSample); + DestroySampleThreadsafe(nSample); mptSample.Initialize(); mptSample.nLength = sampleInfo.numSampleFrames; mptSample.nC5Speed = sampleInfo.GetSampleRate(); @@ -1487,8 +1477,7 @@ { return false; } - CriticalSection cs; - DestroySample(nSample); + DestroySampleThreadsafe(nSample); file.Seek(sampleHeader.ConvertToMPT(Samples[nSample])); StringFixer::ReadString<StringFixer::spacePaddedNull>(m_szNames[nSample], sampleHeader.name); @@ -1790,8 +1779,7 @@ || (pfh->dw8SVX != IFFID_8SVX) || (BigEndian(pfh->dwSize) >= dwFileLength) || (pvh->dwVHDR != IFFID_VHDR) || (BigEndian(pvh->dwSize) >= dwFileLength)) return false; - CriticalSection cs; - DestroySample(nSample); + DestroySampleThreadsafe(nSample); // Default values sample.Initialize(); sample.nLoopStart = BigEndian(pvh->oneShotHiSamples); @@ -1967,13 +1955,16 @@ static void metadata_cb(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data) { FLACDecoder &client = *static_cast<FLACDecoder *>(client_data); + if(client.sample > client.sndFile.GetNumSamples()) + { + client.sndFile.m_nSamples = client.sample; + } ModSample &sample = client.sndFile.GetSample(client.sample); if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0) { // Init sample information - CriticalSection cs; - client.sndFile.DestroySample(client.sample); + client.sndFile.DestroySampleThreadsafe(client.sample); strcpy(client.sndFile.m_szNames[client.sample], ""); sample.Initialize(); sample.uFlags.set(CHN_16BIT, metadata->data.stream_info.bits_per_sample > 8); @@ -2321,8 +2312,8 @@ return false; } - CriticalSection cs; - DestroySample(sample); + DestroySampleThreadsafe(sample); + strcpy(m_szNames[sample], ""); Samples[sample].Initialize(); Samples[sample].nLength = length; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-13 00:33:57 UTC (rev 1524) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-13 15:19:42 UTC (rev 1525) @@ -1547,6 +1547,14 @@ } +bool CSoundFile::DestroySampleThreadsafe(SAMPLEINDEX nSample) +//----------------------------------------------------------- +{ + CriticalSection cs; + return DestroySample(nSample); +} + + void CSoundFile::DeleteStaticdata() //--------------------------------- { @@ -1828,8 +1836,9 @@ for(SAMPLEINDEX i = start; i <= GetModSpecifications().samplesMax; i++) { // When loading into an instrument, ignore non-empty sample names. Else, only use this slot if the sample name is empty or we're in second pass. - if(i > GetNumSamples() - || (Samples[i].pSample == nullptr && (!m_szNames[i][0] || passes == 1 || targetInstrument != INSTRUMENTINDEX_INVALID))) + if((i > GetNumSamples() && passes == 1) + || (Samples[i].pSample == nullptr && (!m_szNames[i][0] || passes == 1 || targetInstrument != INSTRUMENTINDEX_INVALID)) + || (targetInstrument != INSTRUMENTINDEX_INVALID && IsSampleReferencedByInstrument(i, targetInstrument))) // Not empty, but already used by this instrument. { // Empty slot, so it's a good candidate already. Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-13 00:33:57 UTC (rev 1524) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-13 15:19:42 UTC (rev 1525) @@ -606,6 +606,7 @@ public: bool DestroySample(SAMPLEINDEX nSample); + bool DestroySampleThreadsafe(SAMPLEINDEX nSample); // Find an unused sample slot. If it is going to be assigned to an instrument, targetInstrument should be specified. // SAMPLEINDEX_INVLAID is returned if no free sample slot could be found. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-14 18:33:20
|
Revision: 1526 http://sourceforge.net/p/modplug/code/1526 Author: saga-games Date: 2013-02-14 18:33:07 +0000 (Thu, 14 Feb 2013) Log Message: ----------- [Imp] Some more Soundtracker MOD improvements. [Fix] Sample filename wasn't imported properly when loading a FLAC sample with RIFF chunks. [Ref] Moved ID3v1 genres from header to implementation file to get rid of a few more KB. [Mod] OpenMPT: Version is now 1.21.01.12 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/tagging.cpp trunk/OpenMPT/mptrack/tagging.h trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/WAVTools.cpp Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-02-13 15:19:42 UTC (rev 1525) +++ trunk/OpenMPT/common/version.h 2013-02-14 18:33:07 UTC (rev 1526) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 11 +#define VER_MINORMINOR 12 //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/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-02-13 15:19:42 UTC (rev 1525) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-02-14 18:33:07 UTC (rev 1526) @@ -21,6 +21,50 @@ extern UINT nMixingRates[NUMMIXRATE]; extern LPCSTR gszChnCfgNames[3]; +/////////////////////////////////////////////////////////////////////////////////////////////////// +// ID3v1 Genres + +static const char *id3v1GenreNames[] = +{ + "Blues", "Classic Rock", "Country", "Dance", + "Disco", "Funk", "Grunge", "Hip-Hop", + "Jazz", "Metal", "New Age", "Oldies", + "Other", "Pop", "R&B", "Rap", + "Reggae", "Rock", "Techno", "Industrial", + "Alternative", "Ska", "Death Metal", "Pranks", + "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", + "Vocal", "Jazz+Funk", "Fusion", "Trance", + "Classical", "Instrumental", "Acid", "House", + "Game", "Sound Clip", "Gospel", "Noise", + "Alt. Rock", "Bass", "Soul", "Punk", + "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", + "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", + "Electronic", "Pop-Folk", "Eurodance", "Dream", + "Southern Rock", "Comedy", "Cult", "Gangsta", + "Top 40", "Christian Rap", "Pop/Funk", "Jungle", + "Native American", "Cabaret", "New Wave", "Psychadelic", + "Rave", "Showtunes", "Trailer", "Lo-Fi", + "Tribal", "Acid Punk", "Acid Jazz", "Polka", + "Retro", "Musical", "Rock & Roll", "Hard Rock", + "Folk", "Folk-Rock", "National Folk", "Swing", + "Fast Fusion", "Bebob", "Latin", "Revival", + "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", + "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", + "Big Band", "Chorus", "Easy Listening", "Acoustic", + "Humour", "Speech", "Chanson", "Opera", + "Chamber Music", "Sonata", "Symphony", "Booty Bass", + "Primus", "Porn Groove", "Satire", "Slow Jam", + "Club", "Tango", "Samba", "Folklore", + "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", + "Duet", "Punk Rock", "Drum Solo", "A Capella", + "Euro-House", "Dance Hall", "Goa", "Drum & Bass", + "Club House", "Hardcore", "Terror", "Indie", + "BritPop", "Negerpunk", "Polsk Punk", "Beat", + "Christian Gangsta Rap","Heavy Metal", "Black Metal", "Crossover", + "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", + "Thrash Metal", "Anime", "JPop", "Synthpop" +}; + // this converts a buffer of 32-bit integer sample data to 32 bit floating point static void __cdecl M2W_32ToFloat(void *pBuffer, long nCount) { @@ -397,9 +441,9 @@ m_bDriversEnumerated = TRUE; m_CbnDriver.SetCurSel(m_nDriverIndex); if (m_bSaveInfoField) CheckDlgButton(IDC_CHECK3, MF_CHECKED); - for (UINT iGnr=0; iGnr<NUM_GENRES; iGnr++) + for(size_t iGnr = 0; iGnr < CountOf(id3v1GenreNames); iGnr++) { - m_CbnGenre.SetItemData(m_CbnGenre.AddString(gpszGenreNames[iGnr]), iGnr); + m_CbnGenre.SetItemData(m_CbnGenre.AddString(id3v1GenreNames[iGnr]), iGnr); } m_EditYear.SetLimitText(4); Modified: trunk/OpenMPT/mptrack/tagging.cpp =================================================================== --- trunk/OpenMPT/mptrack/tagging.cpp 2013-02-13 15:19:42 UTC (rev 1525) +++ trunk/OpenMPT/mptrack/tagging.cpp 2013-02-14 18:33:07 UTC (rev 1526) @@ -48,7 +48,7 @@ { if(!f) return; - TAGID3v2HEADER tHeader; + ID3v2Header tHeader; UINT fOffset = ftell(f); totalID3v2Size = 0; @@ -110,7 +110,7 @@ sFramecontent = ID3v2_CHARSET + sFramecontent; sFramecontent += ID3v2_TEXTENDING; - TAGID3v2FRAME tFrame; + ID3v2Frame tFrame; memcpy(&tFrame.frameid, cFrameID, 4); // ID tFrame.size = intToSynchsafe(sFramecontent.size()); // Text size @@ -132,12 +132,12 @@ WAVEFILEHEADER list; WAVEDATAHEADER chunk; - DWORD info_ofs, end_ofs; + off_t info_ofs, end_ofs; const uint8 zero = 0; struct { - DWORD id; + uint32 id; string *data; } chunks[] = { Modified: trunk/OpenMPT/mptrack/tagging.h =================================================================== --- trunk/OpenMPT/mptrack/tagging.h 2013-02-13 15:19:42 UTC (rev 1525) +++ trunk/OpenMPT/mptrack/tagging.h 2013-02-14 18:33:07 UTC (rev 1526) @@ -15,74 +15,30 @@ using std::string; -#pragma pack(push, 1) - /////////////////////////////////////////////////////////////////////////////////////////////////// -// ID3v1 Genres +// ID3v2.4 Tags -#define NUM_GENRES 148 +#pragma pack(push, 1) -static LPCSTR gpszGenreNames[NUM_GENRES] = +struct ID3v2Header { - "Blues", "Classic Rock", "Country", "Dance", - "Disco", "Funk", "Grunge", "Hip-Hop", - "Jazz", "Metal", "New Age", "Oldies", - "Other", "Pop", "R&B", "Rap", - "Reggae", "Rock", "Techno", "Industrial", - "Alternative", "Ska", "Death Metal", "Pranks", - "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", - "Vocal", "Jazz+Funk", "Fusion", "Trance", - "Classical", "Instrumental", "Acid", "House", - "Game", "Sound Clip", "Gospel", "Noise", - "Alt. Rock", "Bass", "Soul", "Punk", - "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", - "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", - "Electronic", "Pop-Folk", "Eurodance", "Dream", - "Southern Rock", "Comedy", "Cult", "Gangsta", - "Top 40", "Christian Rap", "Pop/Funk", "Jungle", - "Native American", "Cabaret", "New Wave", "Psychadelic", - "Rave", "Showtunes", "Trailer", "Lo-Fi", - "Tribal", "Acid Punk", "Acid Jazz", "Polka", - "Retro", "Musical", "Rock & Roll", "Hard Rock", - "Folk", "Folk-Rock", "National Folk", "Swing", - "Fast Fusion", "Bebob", "Latin", "Revival", - "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", - "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", - "Big Band", "Chorus", "Easy Listening", "Acoustic", - "Humour", "Speech", "Chanson", "Opera", - "Chamber Music", "Sonata", "Symphony", "Booty Bass", - "Primus", "Porn Groove", "Satire", "Slow Jam", - "Club", "Tango", "Samba", "Folklore", - "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", - "Duet", "Punk Rock", "Drum Solo", "A Capella", - "Euro-House", "Dance Hall", "Goa", "Drum & Bass", - "Club House", "Hardcore", "Terror", "Indie", - "BritPop", "Negerpunk", "Polsk Punk", "Beat", - "Christian Gangsta Rap","Heavy Metal", "Black Metal", "Crossover", - "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", - "Thrash Metal", "Anime", "JPop", "Synthpop" -}; - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// ID3v2.4 Tags - -typedef struct _TAGID3v2HEADER -{ uint8 signature[3]; uint8 version[2]; uint8 flags; uint32 size; // Total: 10 bytes -} TAGID3v2HEADER; +}; -typedef struct _TAGID3v2FRAME +struct ID3v2Frame { uint32 frameid; uint32 size; uint16 flags; // Total: 10 bytes -} TAGID3v2FRAME; +}; +#pragma pack(pop) + // we will add some padding bytes to our id3v2 tag (extending tags will be easier this way) #define ID3v2_PADDING 512 @@ -123,4 +79,3 @@ uint32 totalID3v2Size; }; -#pragma pack(pop) Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-13 15:19:42 UTC (rev 1525) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-14 18:33:07 UTC (rev 1526) @@ -1,7 +1,7 @@ /* * Load_mod.cpp * ------------ - * Purpose: MOD / NST (ProTracker / NoiseTracker) module loader / saver + * Purpose: MOD / NST (ProTracker / NoiseTracker) and M15 / STK (Ultimate Soundtracker / Soundtracker) module loader / saver * Notes : (currently none) * Authors: Olivier Lapicque * OpenMPT Devs @@ -33,8 +33,8 @@ case 0x0D: m.command = CMD_PATTERNBREAK; m.param = ((m.param >> 4) * 10) + (m.param & 0x0F); break; case 0x0E: m.command = CMD_MODCMDEX; break; case 0x0F: - // Speed is 01...1F in XM, but 01...20 in MOD. 15-sample Soundtracker MODs always use VBlank timing, interpret all values as speed. - if(((GetType() & MOD_TYPE_MOD) && (GetNumSamples() == 15 || m.param <= 0x20u)) || (!(GetType() & MOD_TYPE_MOD) && m.param <= 0x1Fu)) + // Speed is 01...1F in XM, but 01...20 in MOD. 15-sample Soundtracker MODs always ignore the high nibble anyway (this is fixed in ReadM15 already) + if(m.param <= ((GetType() & MOD_TYPE_MOD) ? 0x20u : 0x1Fu)) m.command = CMD_SPEED; else m.command = CMD_TEMPO; @@ -236,8 +236,6 @@ { lStart /= 2; } - mptSmp.nLoopStart = lStart; - mptSmp.nLoopEnd = lStart + lLength; if(mptSmp.nLength == 2) { @@ -246,6 +244,9 @@ if(mptSmp.nLength) { + mptSmp.nLoopStart = lStart; + mptSmp.nLoopEnd = lStart + lLength; + if(mptSmp.nLoopStart >= mptSmp.nLength) { mptSmp.nLoopStart = mptSmp.nLength - 1; @@ -265,7 +266,7 @@ { mptSmp.nLoopEnd = 0; } - if (mptSmp.nLoopEnd > mptSmp.nLoopStart) + if(mptSmp.nLoopEnd > mptSmp.nLoopStart) { mptSmp.uFlags.set(CHN_LOOP); } @@ -374,6 +375,14 @@ file.ReadConvertEndianness(sampleHeader); sampleHeader.ConvertToMPT(sample); + // Get rid of weird characters in sample names. + for(size_t i = 0; i < CountOf(sampleHeader.name); i++) + { + if(sampleHeader.name[i] && sampleHeader.name[i] < ' ') + { + sampleHeader.name[i] = ' '; + } + } StringFixer::ReadString<StringFixer::spacePadded>(sampleName, sampleHeader.name); } @@ -409,7 +418,7 @@ Order[ord] = Order.GetInvalidPatIndex(); } - const size_t patternStartOffset = 20 + 31 * sizeof(MODSampleHeader) + sizeof(MODFileHeader) + 4; + const size_t patternStartOffset = file.GetPosition(); const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset; if(checkForWOW) @@ -441,6 +450,26 @@ } +static void ReadPatternEntry(FileReader &file, ModCommand &m, const CSoundFile &sf) +//--------------------------------------------------------------------------------- +{ + uint8 data[4]; + file.ReadArray(data); + + // Read Period + uint16 period = (((static_cast<uint16>(data[0]) & 0x0F) << 8) | data[1]); + if(period > 0 && period != 0xFFF) + { + m.note = static_cast<ModCommand::NOTE>(sf.GetNoteFromPeriod(period * 4)); + } + // Read Instrument + m.instr = (data[2] >> 4) | (data[0] & 0x10); + // Read Effect + m.command = data[2] & 0x0F; + m.param = data[3]; +} + + bool CSoundFile::ReadMod(FileReader &file) //---------------------------------------- { @@ -490,7 +519,7 @@ LimitMax(m_nChannels, MAX_BASECHANNELS); // Startrekker 8 channel mod (needs special treatment, see below) - bool isFLT8 = IsMagic(magic, "FLT8"); + const bool isFLT8 = IsMagic(magic, "FLT8"); // Only apply VBlank tests to M.K. (ProTracker) modules. const bool isMdKd = IsMagic(magic, "M.K."); @@ -531,7 +560,7 @@ } } - // Do some order sanity checks + // Get number of patterns (including some order list sanity checks) PATTERNINDEX numPatterns = GetNumPatterns(file, Order, realOrders, totalSampleLen, m_nChannels, isMdKd); if(isFLT8) @@ -547,9 +576,11 @@ realOrders--; m_nRestartPos = fileHeader.restartPos; - // About the weird 0x78 restart pos thing... I also have no idea where it comes from, XMP also has this check but doesn't comment on it, either. - // It is said that NoiseTracker writes 0x78, but I've also seen this in M15 files. - // Files that have restart pos == 0x78: action's batman by DJ Uno (M.K.), 3ddance.mod (M15), VALLEY.MOD (M.K.), WormsTDC.MOD (M.K.), ZWARTZ.MOD (M.K.) + // (Ultimate) Soundtracker didn't have a restart position, but instead stored a default tempo in this value. + // The default value for this is 0x78 (120 BPM). This is probably the reason why some M.K. modules + // have this weird restart position. I think I've read somewhere that NoiseTracker actually writes 0x78 there. + // Files that have restart pos == 0x78: action's batman by DJ Uno (M.K.), 3ddance.mod (M15, so handled by ReadM15), + // VALLEY.MOD (M.K.), WormsTDC.MOD (M.K.), ZWARTZ.MOD (M.K.) ASSERT(m_nRestartPos != 0x78 || m_nRestartPos + 1u >= realOrders); if(m_nRestartPos >= 128 || m_nRestartPos + 1u >= realOrders || m_nRestartPos == 0x78) { @@ -611,22 +642,8 @@ for(CHANNELINDEX chn = 0; chn < readChannels; chn++) { ModCommand &m = rowBase[chn]; + ReadPatternEntry(file, m, *this); - uint8 data[4]; - file.ReadArray(data); - - // Read Period - uint16 period = (((static_cast<uint16>(data[0]) & 0x0F) << 8) | data[1]); - if(period > 0 && period != 0xFFF) - { - m.note = static_cast<ModCommand::NOTE>(GetNoteFromPeriod(period * 4)); - } - // Read Instrument - m.instr = (data[2] >> 4) | (data[0] & 0x10); - // Read Effect - m.command = data[2] & 0x0F; - m.param = data[3]; - if(m.command || m.param) { ConvertModCommand(m); @@ -730,10 +747,23 @@ // We'll have to do some heuristic checks to find out whether this is an old Ultimate Soundtracker module // or if it was made with the newer Soundtracker versions. - bool isUST = false, isConfirmed = false; + // Thanks for Fraggie for this information! (http://www.un4seen.com/forum/?topic=14471.msg100829#msg100829) + enum STVersions + { + UST1_00, // Ultimate Soundtracker 1.0-1.21 (K. Obarski) + UST1_80, // Ultimate Soundtracker 1.8-2.0 (K. Obarski) + ST2_00_Exterminator, // SoundTracker 2.0 (The Exterminator), D.O.C. Sountracker II (Unknown/D.O.C.) + ST_III, // Defjam Soundtracker III (Il Scuro/Defjam), Alpha Flight SoundTracker IV (Alpha Flight), D.O.C. SoundTracker IV (Unknown/D.O.C.), D.O.C. SoundTracker VI (Unknown/D.O.C.) + ST_IX, // D.O.C. SoundTracker IX (Unknown/D.O.C.) + MST1_00, // Master Soundtracker 1.0 (Tip/The New Masters) + ST2_00, // SoundTracker 2.0, 2.1, 2.2 (Unknown/D.O.C.) + ST2_00_with_Bxx, // Bxx effect found, so definitely SoundTracker 2.0, 2.1, 2.2 (Unknown/D.O.C.) + } minVersion = UST1_00; + bool hasDiskNames = true; size_t totalSampleLen = 0; m_nSamples = 15; + for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { MODSampleHeader sampleHeader; @@ -747,39 +777,21 @@ { return false; } + ASSERT(sampleHeader.finetune == 0); totalSampleLen += Samples[smp].nLength; - if(isConfirmed) + if(m_szNames[smp][0] && ((memcmp(m_szNames[smp], "st-", 3) && memcmp(m_szNames[smp], "ST-", 3)) || m_szNames[smp][0] < '0' || m_szNames[smp][0] > '9')) { - continue; + // Ultimate Soundtracker 1.8 and D.O.C. SoundTracker IX always have sample names containing disk names. + hasDiskNames = false; } - // Soundtracker sample names should always start with "S", "ST-" or a number, but for UST mods, this is not the case. - // sll17.3.mod from ModLand has Soundtracker pattern effects but no "st-" sample names. Is this a bad / modified rip? - if((memcmp(sampleHeader.name, "st-", 3) && memcmp(sampleHeader.name, "ST-", 3)) || sampleHeader.name[0] < '0' || sampleHeader.name[0] > '9') - { - isUST = true; - } - - // UST only handles samples up to 9999 bytes. + // UST only handles samples up to 9999 bytes. Master Soundtracker 1.0 and SoundTracker 2.0 introduce 32KB samples. if(sampleHeader.length > 4999 || sampleHeader.loopStart > 9999) { - isUST = false; + minVersion = Util::Max(minVersion, MST1_00); } - // If loop information is incorrect as words, but correct as bytes, this is likely to be an UST-style module - if(sampleHeader.loopStart + sampleHeader.loopLength > sampleHeader.length - && sampleHeader.loopStart + sampleHeader.loopLength < sampleHeader.length * 2) - { - isUST = true; - isConfirmed = true; - continue; - } - - if(!isUST) - { - isConfirmed = true; - } } MODFileHeader fileHeader; @@ -814,11 +826,31 @@ m_nChannels = 4; m_nInstruments = 0; m_nDefaultSpeed = 6; - m_nDefaultTempo = 125; + if(fileHeader.restartPos <= 0x40) + { + m_nDefaultTempo = 125; + m_nRestartPos = (fileHeader.restartPos < fileHeader.numOrders ? fileHeader.restartPos : 0); + } else + { + // Sample 7 in echoing.mod won't "loop" correctly if we don't convert the tempo. + m_nDefaultTempo = fileHeader.restartPos * 25 / 24; + m_nRestartPos = 0; + if(fileHeader.restartPos != 0x78) + { + if(minVersion > UST1_80) + { + // D.O.C. SoundTracker IX re-introduced the variable tempo after some other versions dropped it. + minVersion = Util::Max(minVersion, hasDiskNames ? ST_IX : MST1_00); + } else + { + // Ultimate Soundtracker 1.8 adds variable tempo + minVersion = Util::Max(minVersion, hasDiskNames ? UST1_80 : ST2_00_Exterminator); + } + } + } m_nMinPeriod = 14 * 4; m_nMaxPeriod = 3424 * 4; m_SongFlags.reset(); - m_nRestartPos = (fileHeader.restartPos < fileHeader.numOrders ? fileHeader.restartPos : 0); StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], songname); // Setup channel pan positions and volume @@ -833,25 +865,35 @@ file.ReadArray(data); const uint8 eff = data[2] & 0x0F, param = data[3]; - if((eff == 1 || eff == 2) && param > 0x1F) + switch(eff) { - // If a 1xx effect has a parameter greater than 0x20, it is assumed to be UST. - isUST = true; + case 1: + case 2: + if(param > 0x1F && minVersion == UST1_80) + { + // If a 1xx / 2xx effect has a parameter greater than 0x20, it is assumed to be UST. + minVersion = hasDiskNames ? UST1_80 : UST1_00; + } else if(eff == 1 && param < 0x03) + { + // This doesn't look like an arpeggio. + minVersion = Util::Max(minVersion, ST2_00_Exterminator); + } break; - } else if(eff == 1 && param < 0x03) - { - // MikMod says so! Well, it makes sense, kind of... who would want an arpeggio like this? - isUST = false; + case 0x0B: + minVersion = Util::Max(minVersion, ST2_00_with_Bxx); break; - } else if(eff == 3 && param != 0) - { - // MikMod says so! - isUST = false; + case 0x0C: + case 0x0D: + case 0x0E: + minVersion = Util::Max(minVersion, ST2_00_Exterminator); + if(eff == 0x0D && param == 0) + { + // Assume this is a pattern break command. + minVersion = Util::Max(minVersion, ST2_00); + } break; - } else if(eff > 3) - { - // Unknown effect - isUST = false; + case 0x0F: + minVersion = Util::Max(minVersion, ST_III); break; } } @@ -866,41 +908,51 @@ break; } - uint8 lastEff[4] = { 0, 0, 0, 0 }, lastParam[4] = { 0, 0, 0, 0 }; - for(ROWINDEX row = 0; row < 64; row++) { ModCommand *rowBase = Patterns[pat].GetpModCommand(row, 0); for(CHANNELINDEX chn = 0; chn < 4; chn++) { ModCommand &m = rowBase[chn]; + ReadPatternEntry(file, m, *this); - uint8 data[4]; - file.ReadArray(data); - - // Read Period - uint16 period = (((static_cast<uint16>(data[0]) & 0x0F) << 8) | data[1]); - if(period > 0 && period != 0xFFF) - { - m.note = static_cast<ModCommand::NOTE>(GetNoteFromPeriod(period * 4)); - } - // Read Instrument - m.instr = (data[2] >> 4) | (data[0] & 0x10); - // Read Effect - m.command = data[2] & 0x0F; - m.param = data[3]; - if(m.command || m.param) { - if(isUST) + if(m.command == 0x0D) { + if(m.param != 0 || minVersion < ST_IX) + { + // Dxy is volume slide in some Soundtracker versions, D00 is a pattern break in the latest versions. + m.command = 0x0A; + } else if(m.param == 0 && row == 0 && minVersion != ST2_00_with_Bxx) + { + // Fix a possible tracking mistake in Blood Money title - who wants to do a pattern break on the first row anyway? + m.command = m.param = 0; + } else + { + m.param = 0; + } + } else if(m.command == 0x0E && (m.param > 0x01 || minVersion < ST_IX)) + { + // Import auto-slides as normal slides and ignore their extended behaviour. + m.command = 0x0A; + } else if(m.command == 0x0F) + { + // Only the low nibble is evaluated in Soundtracker. + m.param &= 0x0F; + } + + if(minVersion <= UST1_80) + { // UST effects switch(m.command) { case 0: - case 3: - m.command = CMD_NONE; - break; + // jackdance.mod by Karsten Obarski has 0xy arpeggios... + if(m.param < 0x03) + { + break; + } case 1: m.command = CMD_ARPEGGIO; break; @@ -909,34 +961,18 @@ { m.command = CMD_PORTAMENTOUP; m.param &= 0x0F; - } else if(m.param >> 2) + } else if(m.param >> 4) { m.command = CMD_PORTAMENTODOWN; - m.param >>= 2; + m.param >>= 4; } break; default: - ConvertModCommand(m); + m.command = CMD_NONE; break; } } else { - // M15 effects - if((m.command == 1 || m.command == 2 || m.command == 3) && m.param == 0) - { - // An isolated 100, 200 or 300 effect should be ignored (no "standalone" porta memory in mod files). - // However, a sequence such as 1xx, 100, 100, 100 is fine. - if(m.command != lastEff[chn] || lastParam[chn] == 0) - { - m.command = m.param = 0; - } else - { - m.param = lastParam[chn]; - } - } - lastEff[chn] = m.command; - lastParam[chn] = m.param; - ConvertModCommand(m); } } @@ -947,15 +983,12 @@ // Reading samples for(SAMPLEINDEX smp = 1; smp <= 15; smp++) { - if(isUST) - { - // Looped samples in Ultimate Soundtracker seem to ignore all sample data before the actual loop start. - // This avoids the clicks in the first sample of pretend.mod by Karsten Obarski. - file.Skip(Samples[smp].nLoopStart); - Samples[smp].nLength -= Samples[smp].nLoopStart; - Samples[smp].nLoopEnd -= Samples[smp].nLoopStart; - Samples[smp].nLoopStart = 0; - } + // Looped samples in (Ultimate) Soundtracker seem to ignore all sample data before the actual loop start. + // This avoids the clicks in the first sample of pretend.mod by Karsten Obarski. + file.Skip(Samples[smp].nLoopStart); + Samples[smp].nLength -= Samples[smp].nLoopStart; + Samples[smp].nLoopEnd -= Samples[smp].nLoopStart; + Samples[smp].nLoopStart = 0; MODSampleHeader::GetSampleFormat().ReadSample(Samples[smp], file); } @@ -1047,7 +1080,7 @@ // Write magic bytes char modMagic[6]; - CHANNELINDEX writeChannels = min(99, GetNumChannels()); + CHANNELINDEX writeChannels = Util::Min(CHANNELINDEX(99), GetNumChannels()); if(writeChannels == 4) { if(writePatterns < 64) @@ -1149,7 +1182,7 @@ static const int8 silence[] = {0, 0}; - if((sample.uFlags & CHN_LOOP) == 0) + if(!sample.uFlags[CHN_LOOP]) { // First two bytes of oneshot samples have to be 0 due to PT's one-shot loop const long sampleEnd = ftell(f); Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-13 15:19:42 UTC (rev 1525) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-14 18:33:07 UTC (rev 1526) @@ -91,9 +91,9 @@ // For WAV export (writing pattern positions to file) struct PatternCuePoint { - bool processed; // has this point been processed by the main WAV render function yet? ULONGLONG offset; // offset in the file (in samples) ORDERINDEX order; // which order is this? + bool processed; // has this point been processed by the main WAV render function yet? }; @@ -101,11 +101,11 @@ struct GetLengthType { double duration; // total time in seconds - bool targetReached; // true if the specified order/row combination has been reached while going through the module + ROWINDEX lastRow; // last parsed row (dito) + ROWINDEX endRow; // last row before module loops (dito) ORDERINDEX lastOrder; // last parsed order (if no target is specified, this is the first order that is parsed twice, i.e. not the *last* played order) - ROWINDEX lastRow; // last parsed row (dito) ORDERINDEX endOrder; // last order before module loops (UNDEFINED if a target is specified) - ROWINDEX endRow; // last row before module loops (dito) + bool targetReached; // true if the specified order/row combination has been reached while going through the module }; Modified: trunk/OpenMPT/soundlib/WAVTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.cpp 2013-02-13 15:19:42 UTC (rev 1525) +++ trunk/OpenMPT/soundlib/WAVTools.cpp 2013-02-14 18:33:07 UTC (rev 1526) @@ -22,6 +22,7 @@ file.Rewind(); RIFFHeader fileHeader; + isDLS = false; if(!file.ReadConvertEndianness(fileHeader) || (fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST) || (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave)) @@ -35,7 +36,7 @@ if(chunks.size() >= 4 && chunks[1].GetHeader().GetID() == RIFFChunk::iddata - && chunks[1].GetHeader().GetLength() % 2 != 0 + && chunks[1].GetHeader().GetLength() % 2u != 0 && chunks[2].GetHeader().GetLength() == 0 && chunks[3].GetHeader().GetID() == RIFFChunk::id____) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-15 16:01:32
|
Revision: 1527 http://sourceforge.net/p/modplug/code/1527 Author: saga-games Date: 2013-02-15 16:01:20 +0000 (Fri, 15 Feb 2013) Log Message: ----------- [New] VST: Can now load and save FXB files. Modified Paths: -------------- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/mptrack/Vstplug.h trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/soundlib/plugins/JBridge.cpp Added Paths: ----------- trunk/OpenMPT/mptrack/VstPresets.cpp trunk/OpenMPT/mptrack/VstPresets.h Removed Paths: ------------- trunk/OpenMPT/mptrack/fxp.cpp trunk/OpenMPT/mptrack/fxp.h Modified: trunk/OpenMPT/mptrack/AbstractVstEditor.cpp =================================================================== --- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2013-02-15 16:01:20 UTC (rev 1527) @@ -14,7 +14,6 @@ #include "mainfrm.h" #include "sndfile.h" #include "vstplug.h" -#include "fxp.h" #include "dlg_misc.h" #include "AbstractVstEditor.h" #include "../common/StringFixer.h" @@ -105,20 +104,24 @@ if(!m_pVstPlugin) return; FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(true, "fxp", "", - "VST Program (*.fxp)|*.fxp||", + "VST Plugin Programs and Banks (*.fxp,*.fbx)|*.fxp;*.fxb|" + "VST Plugin Programs (*.fxp)|*.fxp|" + "VST Plugin Banks (*.fxb)|*.fxb|" + "All Files|*.*||", CMainFrame::GetSettings().GetWorkingDirectory(DIR_PLUGINPRESETS)); if(files.abort) return; CMainFrame::GetSettings().SetWorkingDirectory(files.workingDirectory.c_str(), DIR_PLUGINPRESETS, true); - //TODO: exception handling to distinguish errors at this level. - if (m_pVstPlugin->LoadProgram(files.first_file.c_str())) + const char *retVal = m_pVstPlugin->LoadProgram(files.first_file.c_str()); + if(retVal == nullptr) { if(m_pVstPlugin->GetModDoc() != nullptr) m_pVstPlugin->GetModDoc()->SetModified(); + UpdatePresetField(); } else { - Reporting::Error("Error loading preset. Are you sure it is for this plugin?"); + Reporting::Error(retVal, "Plugin Preset"); } } @@ -129,7 +132,8 @@ if(!m_pVstPlugin) return; FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(false, "fxp", "", - "VST Program (*.fxp)|*.fxp||", + "VST Plugin Programs (*.fxp)|*.fxp|" + "VST Plugin Banks (*.fxb)|*.fxb||", CMainFrame::GetSettings().GetWorkingDirectory(DIR_PLUGINPRESETS)); if(files.abort) return; Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2013-02-15 16:01:20 UTC (rev 1527) @@ -1034,21 +1034,22 @@ } FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(true, "fxp", "", - "VST FX Program (*.fxp)|*.fxp||", + "VST Plugin Programs and Banks (*.fxp,*.fbx)|*.fxp;*.fxb|" + "VST Plugin Programs (*.fxp)|*.fxp|" + "VST Plugin Banks (*.fxb)|*.fxb|" + "All Files|*.*||", CMainFrame::GetSettings().GetDefaultDirectory(DIR_PLUGINPRESETS)); if(files.abort) return; - - //TODO: exception handling - if (!(pVstPlugin->LoadProgram(files.first_file.c_str()))) + + const char *retVal = pVstPlugin->LoadProgram(files.first_file.c_str()); + if(retVal == nullptr) { - Reporting::Error("Error loading preset. Are you sure it is for this plugin?"); + if(pSndFile->GetModSpecifications().supportsPlugins) + pModDoc->SetModified(); } else { - if(pSndFile->GetModSpecifications().supportsPlugins) - pModDoc->SetModified(); + Reporting::Error(retVal, "Plugin Preset"); } - - //end rewbs.fxpPresets } void CViewGlobals::OnSaveParam() @@ -1068,7 +1069,8 @@ return; } FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(false, "fxp", "", - "VST Program (*.fxp)|*.fxp||", + "VST Plugin Programs (*.fxp)|*.fxp|" + "VST Plugin Banks (*.fxb)|*.fxb||", CMainFrame::GetSettings().GetDefaultDirectory(DIR_PLUGINPRESETS)); if(files.abort) return; Added: trunk/OpenMPT/mptrack/VstPresets.cpp =================================================================== --- trunk/OpenMPT/mptrack/VstPresets.cpp (rev 0) +++ trunk/OpenMPT/mptrack/VstPresets.cpp 2013-02-15 16:01:20 UTC (rev 1527) @@ -0,0 +1,253 @@ +/* + * VstPresets.cpp + * -------------- + * Purpose: VST plugin preset / bank handling + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" + +#ifndef NO_VST +#include "Sndfile.h" +#include "Vstplug.h" +#include <vstsdk2.4/pluginterfaces/vst2.x/vstfxstore.h> +#include "VstPresets.h" + + +// This part of the header is identical for both presets and banks. +struct ChunkHeader +{ + VstInt32 chunkMagic; ///< 'CcnK' + VstInt32 byteSize; ///< size of this chunk, excl. magic + byteSize + + VstInt32 fxMagic; ///< 'FxBk' (regular) or 'FBCh' (opaque chunk) + VstInt32 version; ///< format version (1 or 2) + VstInt32 fxID; ///< fx unique ID + VstInt32 fxVersion; ///< fx version + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesBE(chunkMagic); + SwapBytesBE(byteSize); + SwapBytesBE(fxMagic); + SwapBytesBE(version); + SwapBytesBE(fxID); + SwapBytesBE(fxVersion); + } +}; + + +VSTPresets::ErrorCode VSTPresets::LoadFile(FileReader &file, CVstPlugin &plugin) +//------------------------------------------------------------------------------ +{ + const bool firstChunk = file.GetPosition() == 0; + ChunkHeader header; + if(!file.ReadConvertEndianness(header) || header.chunkMagic != cMagic) + { + return invalidFile; + } + if(header.fxID != plugin.GetUID()) + { + return wrongPlugin; + } + if(header.fxVersion > plugin.GetVersion()) + { + return outdatedPlugin; + } + + if(header.fxMagic == fMagic || header.fxMagic == chunkPresetMagic) + { + // Program + PlugParamIndex numParams = file.ReadUint32BE(); + char prgName[28]; + file.ReadString<StringFixer::maybeNullTerminated>(prgName, 28); + plugin.Dispatch(effSetProgramName, 0, 0, prgName, 0.0f); + + if(header.fxMagic == fMagic) + { + if(plugin.GetNumParameters() != numParams) + { + return wrongParameters; + } + for(PlugParamIndex p = 0; p < numParams; p++) + { + plugin.SetParameter(p, file.ReadFloatBE()); + } + } else + { + FileReader chunk = file.GetChunk(file.ReadUint32BE()); + plugin.Dispatch(effSetChunk, 1, chunk.GetLength(), const_cast<char *>(chunk.GetRawData()), 0); + } + } else if((header.fxMagic == bankMagic || header.fxMagic == chunkBankMagic) && firstChunk) + { + // Bank - only read if it's the first chunk in the file, not if it's a sub chunk. + uint32 numProgs = file.ReadUint32BE(); + uint32 currentProgram = file.ReadUint32BE(); + file.Skip(124); + + if(header.fxMagic == bankMagic) + { + VstInt32 oldCurrentProgram = plugin.GetCurrentProgram(); + for(uint32 p = 0; p < numProgs; p++) + { + plugin.SetCurrentProgram(p); + ErrorCode retVal = LoadFile(file, plugin); + if(retVal != noError) + { + return retVal; + } + } + plugin.SetCurrentProgram(oldCurrentProgram); + } else + { + FileReader chunk = file.GetChunk(file.ReadUint32BE()); + plugin.Dispatch(effSetChunk, 0, chunk.GetLength(), const_cast<char *>(chunk.GetRawData()), 0); + } + if(header.version >= 2) + { + plugin.SetCurrentProgram(currentProgram); + } + } + + return noError; +} + + +bool VSTPresets::SaveFile(const char *filename, CVstPlugin &plugin, bool bank) +//---------------------------------------------------------------------------- +{ + FILE *f = fopen(filename, "wb"); + if(f == nullptr) + { + return false; + } + + if(!bank) + { + SaveProgram(f, plugin); + } else + { + const bool writeChunk = plugin.ProgramsAreChunks(); + ChunkHeader header; + header.chunkMagic = cMagic; + header.fxMagic = writeChunk ? chunkBankMagic : bankMagic; + header.version = 2; + header.fxID = plugin.GetUID(); + header.fxVersion = plugin.GetVersion(); + + // Write unfinished header... We need to update the size once we're done writing. + fwrite(&header, sizeof(header), 1, f); + + uint32 numProgs = plugin.GetNumPrograms(), curProg = plugin.GetCurrentProgram(); + WriteBE(numProgs, f); + WriteBE(curProg, f); + char reserved[124]; + MemsetZero(reserved); + Write(reserved, f); + + if(writeChunk) + { + void *chunk = nullptr; + uint32 chunkSize = plugin.Dispatch(effGetChunk, 0, 0, &chunk, 0); + if(chunkSize && chunk) + { + WriteBE(chunkSize, f); + fwrite(chunk, chunkSize, 1, f); + } + } else + { + for(uint32 p = 0; p < numProgs; p++) + { + plugin.SetCurrentProgram(p); + SaveProgram(f, plugin); + } + plugin.SetCurrentProgram(curProg); + } + + // Now we know the correct chunk size. + off_t end = ftell(f); + header.byteSize = end - 8; + header.ConvertEndianness(); + fseek(f, 0, SEEK_SET); + fwrite(&header, sizeof(header), 1, f); + } + + fclose(f); + return true; +} + + +void VSTPresets::SaveProgram(FILE *f, CVstPlugin &plugin) +//------------------------------------------------------- +{ + const bool writeChunk = plugin.ProgramsAreChunks(); + ChunkHeader header; + header.chunkMagic = cMagic; + header.fxMagic = writeChunk ? chunkPresetMagic : fMagic; + header.version = 1; + header.fxID = plugin.GetUID(); + header.fxVersion = plugin.GetVersion(); + + // Write unfinished header... We need to update the size once we're done writing. + off_t start = ftell(f); + fwrite(&header, sizeof(header), 1, f); + + const uint32 numParams = plugin.GetNumParameters(); + WriteBE(numParams, f); + + char name[max(kVstMaxProgNameLen + 1, 256)]; + plugin.Dispatch(effGetProgramName, 0, 0, name, 0); + fwrite(name, 28, 1, f); + + if(writeChunk) + { + void *chunk = nullptr; + uint32 chunkSize = plugin.Dispatch(effGetChunk, 1, 0, &chunk, 0); + if(chunkSize && chunk) + { + WriteBE(chunkSize, f); + fwrite(chunk, chunkSize, 1, f); + } + } else + { + for(uint32 p = 0; p < numParams; p++) + { + WriteBE(plugin.GetParameter(p), f); + } + } + + // Now we know the correct chunk size. + off_t end = ftell(f); + header.byteSize = end - start - 8; + header.ConvertEndianness(); + fseek(f, start, SEEK_SET); + fwrite(&header, sizeof(header), 1, f); + fseek(f, end, SEEK_SET); +} + + +void VSTPresets::WriteBE(uint32 v, FILE *f) +//----------------------------------------- +{ + SwapBytesBE(v); + Write(v, f); +} + + +void VSTPresets::WriteBE(float v, FILE *f) +//---------------------------------------- +{ + union + { + float f; + uint32 i; + } u; + u.f = v; + WriteBE(u.i, f); +} + +#endif // NO_VST Added: trunk/OpenMPT/mptrack/VstPresets.h =================================================================== --- trunk/OpenMPT/mptrack/VstPresets.h (rev 0) +++ trunk/OpenMPT/mptrack/VstPresets.h 2013-02-15 16:01:20 UTC (rev 1527) @@ -0,0 +1,45 @@ +/* + * VstPresets.h + * ------------ + * Purpose: VST plugin preset / bank handling + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#pragma once + +class VSTPresets +{ +public: + enum ErrorCode + { + noError, + invalidFile, + wrongPlugin, + outdatedPlugin, + wrongParameters, + }; + +#ifndef NO_VST + static ErrorCode LoadFile(FileReader &file, CVstPlugin &plugin); + static bool SaveFile(const char *filename, CVstPlugin &plugin, bool bank); + +protected: + static void SaveProgram(FILE *f, CVstPlugin &plugin); + + template<typename T> + static void Write(const T &v, FILE *f) + { + fwrite(&v, sizeof(T), 1, f); + } + + static void WriteBE(uint32 v, FILE *f); + static void WriteBE(float v, FILE *f); + +#else + static ErrorCode LoadFile(FileReader &, CVstPlugin &) { return invalidFile; } + static bool SaveFile(const char *, CVstPlugin &, bool) { return false; } +#endif // NO_VST +}; Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2013-02-15 16:01:20 UTC (rev 1527) @@ -15,10 +15,9 @@ #include <medparam.h> #include "mainfrm.h" #include "vstplug.h" -#include <pluginterfaces/vst2.x/vstfxstore.h> // VST Presets +#include "VstPresets.h" #include "moddoc.h" #include "sndfile.h" -#include "fxp.h" //rewbs.VSTpresets #include "AbstractVstEditor.h" //rewbs.defaultPlugGUI #include "VstEditor.h" //rewbs.defaultPlugGUI #include "defaultvsteditor.h" //rewbs.defaultPlugGUI @@ -1597,8 +1596,8 @@ } -VstInt32 CVstPlugin::GetUID() -//--------------------------- +VstInt32 CVstPlugin::GetUID() const +//--------------------------------- { if (!(m_pEffect)) return 0; @@ -1606,8 +1605,8 @@ } -VstInt32 CVstPlugin::GetVersion() -//------------------------------- +VstInt32 CVstPlugin::GetVersion() const +//------------------------------------- { if (!(m_pEffect)) return 0; @@ -1654,77 +1653,45 @@ } -bool CVstPlugin::SaveProgram(CString fileName) -//-------------------------------------------- +bool CVstPlugin::SaveProgram(const char *filename) +//------------------------------------------------ { - if (!(m_pEffect)) - return false; + char ext[_MAX_EXT]; + _splitpath(filename, nullptr, nullptr, nullptr, ext); + return VSTPresets::SaveFile(filename, *this, !_strnicmp(ext, ".fxb", 4)); +} - bool success; - // Collect required data - long ID = GetUID(); - long plugVersion = GetVersion(); - Cfxp* fxp = nullptr; - - // Construct & save fxp - - // try chunk-based preset: - if((m_pEffect->flags & effFlagsProgramChunks) != 0) +const char *CVstPlugin::LoadProgram(const char *filename) +//------------------------------------------------------- +{ + CMappedFile f; + if(!f.Open(filename)) { - void *chunk = nullptr; - long chunkSize = Dispatch(effGetChunk, 1,0, &chunk, 0); - if(chunkSize && chunk) - fxp = new Cfxp(ID, plugVersion, 1, chunkSize, chunk); + return "Can't open file."; } - // fall back on parameter based preset: - if(fxp == nullptr) - { - // Collect required data - PlugParamIndex numParams = GetNumParameters(); - float *params = new float[numParams]; - GetParams(params, 0, numParams); + size_t len = f.GetLength(); + const char *data = reinterpret_cast<const char *>(f.Lock(len)); + FileReader file(data, len); - fxp = new Cfxp(ID, plugVersion, numParams, params); + VSTPresets::ErrorCode error = VSTPresets::LoadFile(file, *this); + f.Close(); - delete[] params; - } - - success = fxp->Save(fileName); - if(fxp) - delete fxp; - - return success; - -} - - -bool CVstPlugin::LoadProgram(CString fileName) -//-------------------------------------------- -{ - if (!(m_pEffect)) - return false; - - Cfxp fxp(fileName); // load from file - - // Verify - if (m_pEffect->uniqueID != fxp.fxID) - return false; - - if (fxp.fxMagic == fMagic) // Load preset based fxp + switch(error) { - if (m_pEffect->numParams != fxp.numParams) - return false; - for (int p=0; p<fxp.numParams; p++) - SetParameter(p, fxp.params[p]); - } else if (fxp.fxMagic == chunkPresetMagic) - { - Dispatch(effSetChunk, 1, fxp.chunkSize, (BYTE*)fxp.chunk, 0); + case VSTPresets::noError: + default: + return nullptr; + case VSTPresets::invalidFile: + return "This does not appear to be a valid preset file."; + case VSTPresets::wrongPlugin: + return "This file appears to be for a different plugin."; + case VSTPresets::outdatedPlugin: + return "This file is for a newer version of this plugin."; + case VSTPresets::wrongParameters: + return "The number of parameters in this file is incompatible with the current plugin."; } - - return true; } -//end rewbs.VSTpresets VstIntPtr CVstPlugin::Dispatch(VstInt32 opCode, VstInt32 index, VstIntPtr value, void *ptr, float opt) @@ -2651,8 +2618,7 @@ { m_pMixStruct->defaultProgram = -1; - if ((m_pEffect->flags & effFlagsProgramChunks) - && (Dispatch(effIdentify, 0,0, nullptr, 0.0f) == 'NvEf')) + if(ProgramsAreChunks() && Dispatch(effIdentify, 0,0, nullptr, 0.0f) == 'NvEf') { void *p = nullptr; LONG nByteSize = 0; Modified: trunk/OpenMPT/mptrack/Vstplug.h =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.h 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/Vstplug.h 2013-02-15 16:01:20 UTC (rev 1527) @@ -180,10 +180,12 @@ VstInt32 GetCurrentProgram(); VstInt32 GetNumProgramCategories(); CString GetFormattedProgramName(VstInt32 index, bool allowFallback = false); - bool LoadProgram(CString fileName); - bool SaveProgram(CString fileName); - VstInt32 GetUID(); - VstInt32 GetVersion(); + const char *LoadProgram(const char *filename); + bool SaveProgram(const char *filename); + VstInt32 GetUID() const; + VstInt32 GetVersion() const; + // Check if programs should be stored as chunks or parameters + bool ProgramsAreChunks() const { return m_pEffect && (m_pEffect->flags & effFlagsProgramChunks) != 0; } bool GetParams(float* param, VstInt32 min, VstInt32 max); bool RandomizeParams(PlugParamIndex minParam = 0, PlugParamIndex maxParam = 0); #ifdef MODPLUG_TRACKER @@ -292,7 +294,9 @@ bool GetProgramNameIndexed(long, long, char*) { return false; } CString GetFormattedProgramName(VstInt32, bool = false) { return ""; } void SetParameter(PlugParamIndex, PlugParamValue) {} - + VstInt32 GetUID() const { return 0; } + VstInt32 GetVersion() const { return 0; } + bool CanAutomateParameter(PlugParamIndex index) { return false; } CString GetFormattedParamName(PlugParamIndex) { return ""; }; @@ -302,8 +306,8 @@ CString GetParamDisplay(PlugParamIndex) { return ""; }; PlugParamValue GetParameter(PlugParamIndex) { return 0; } - bool LoadProgram(CString) {return false;} - bool SaveProgram(CString) {return false;} + const char *LoadProgram(const char *) { return false; } + bool SaveProgram(const char *) { return false; } void SetCurrentProgram(UINT) {} void SetSlot(UINT) {} void UpdateMixStructPtr(void*) {} Deleted: trunk/OpenMPT/mptrack/fxp.cpp =================================================================== --- trunk/OpenMPT/mptrack/fxp.cpp 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/fxp.cpp 2013-02-15 16:01:20 UTC (rev 1527) @@ -1,307 +0,0 @@ -#include "stdafx.h" -#include "fxp.h" -#include "../common/Reporting.h" - -/************************************ -* Cons/Dest -*************************************/ - -Cfxp::Cfxp(void) -//-------------- -{ - params=NULL; - chunk=NULL; - m_bNeedSwap=-1; -} - -Cfxp::Cfxp(CString fileName) -//-------------------------- -{ - //Cfxp(); - params=NULL; - chunk=NULL; - m_bNeedSwap=-1; - Load(fileName); -} - - -Cfxp::Cfxp(long ID, long version, long nParams, float *ps) -//-------------------------------------------------------- -{ - //Cfxp(); - params=NULL; - chunk=NULL; - m_bNeedSwap=-1; - - ChunkMagic='CcnK'; // 'KncC'; - fxMagic='FxCk'; // 'kCxF'; - byteSize=0; - version=2; - fxID=ID; - fxVersion=version; - numParams=nParams; - params = new float[numParams]; - - memcpy(params, ps, sizeof(float)*numParams); - memset(prgName, 0, 28); -} - -Cfxp::Cfxp(long ID, long plugVersion, long nPrograms, long inChunkSize, void *inChunk) -//-------------------------------------------------------------------------------- -{ - //Cfxp(); - params=NULL; - chunk=NULL; - m_bNeedSwap=-1; - - ChunkMagic='CcnK'; // 'KncC'; - fxMagic='FPCh'; - byteSize = inChunkSize + 52; //52 is: header without byteSize and fxMagic. - version=2; - fxID=ID; - fxVersion=plugVersion; - numParams=nPrograms; - chunkSize=inChunkSize; - chunk = malloc(chunkSize); - memcpy(chunk, inChunk, sizeof(char)*chunkSize); - memset(prgName, 0, 28); -} - - -Cfxp::~Cfxp(void) -{ - delete[] params; - free(chunk); -} - - -/************************************ -* Load/Save -*************************************/ - - -bool Cfxp::Load(CString fileName) -{ - //char s[256]; - CFile inStream; - CFileException e; - if ( !inStream.Open(fileName, CFile::modeRead, &e) ) - { - //TODO: exception - Reporting::Error("Error opening file."); - return false; - } - - //TODO: make ReadLE OO (extend CFILE); - //TODO: exceptions - if (!(ReadLE(inStream, ChunkMagic) && - ReadLE(inStream, byteSize) && - ReadLE(inStream, fxMagic) && - ReadLE(inStream, version) && - ReadLE(inStream, fxID) && - ReadLE(inStream, fxVersion) && - ReadLE(inStream, numParams) && - ReadLE(inStream, prgName, 28) && - ChunkMagic == 'CcnK' && - (fxMagic == 'FxCk' || fxMagic == 'FPCh'))) - { - Reporting::Error("Bad Magic number: this does not look like a preset file."); - inStream.Close(); - return false; - } - - if (fxMagic == 'FxCk') // load param list - { - params = new float[numParams]; - for (int p=0; p<numParams; p++) - { - if (!ReadLE(inStream, params[p])) - { - Reporting::Error("Error reading Params."); - inStream.Close(); - return false; - } - } - } - else if (fxMagic == 'FPCh') // load chunk - { - if (!ReadLE(inStream, chunkSize)) - { - Reporting::Error("Error reading chunk size."); - inStream.Close(); - return false; - } - - chunk = malloc(chunkSize); - - if (!chunk) - { - Reporting::Error("Error allocating memory for chunk."); - inStream.Close(); - return false; - } - - if (!ReadLE(inStream, (char*)chunk, chunkSize)) - { - Reporting::Error("Error reading chunk."); - inStream.Close(); - return false; - } - - } - - inStream.Close(); - return true; -} - -bool Cfxp::Save(CString fileName) -{ - CFile outStream; - CFileException e; - - if ( !outStream.Open(fileName, CFile::modeCreate | CFile::modeWrite, &e) ) - { - //TODO: exception - return false; - } - - //TODO: make ReadLE OO (override CFILE); - //TODO: exceptions - if (!(WriteLE(outStream, ChunkMagic) && - WriteLE(outStream, byteSize) && - WriteLE(outStream, fxMagic) && - WriteLE(outStream, version) && - WriteLE(outStream, fxID) && - WriteLE(outStream, fxVersion) && - WriteLE(outStream, numParams) && - WriteLE(outStream, prgName, 28))) - { - outStream.Close(); - return false; - } - - if (fxMagic == 'FxCk') // save param list - { - for (int p=0; p<numParams; p++) - { - if (!WriteLE(outStream, params[p])) - { - //TODO: exception - outStream.Close(); - return false; - } - } - } - else if (fxMagic == 'FPCh') // save chunk list - { - if (!WriteLE(outStream, chunkSize) || !WriteLE(outStream, (char*)chunk, chunkSize)) - { - //TODO: exception - outStream.Close(); - return false; - } - - } - - outStream.Close(); - return true; -} - -/************************************ -* Util -*************************************/ - -bool Cfxp::ReadLE(CFile &in, long &l) -{ - UINT size=sizeof(long); - if (in.Read(&l, size) < size) - return false; - - if (NeedSwap()) - SwapBytes(l); - return true; -} - -bool Cfxp::ReadLE(CFile &in, float &f) -{ - UINT size=sizeof(float); - - try { - if (in.Read(&f, size) < size) - return false; - } catch (CFileException *e) - { - char s[256]; - wsprintf(s, "%lx: %d; %d; %s;", e, e->m_cause, e->m_lOsError, (LPCTSTR)e->m_strFileName); - Reporting::Error(s); - e->Delete(); - } - - if (NeedSwap()) - SwapBytes(f); - return true; - -} - -bool Cfxp::ReadLE(CFile &in, char *c, UINT length) -{ - UINT size=sizeof(char)*length; - return (in.Read(c, size) >= size); -} - -bool Cfxp::WriteLE(CFile &out, const long &l) -{ - int size=sizeof(long); - long l2 = l; - if (NeedSwap()) - SwapBytes(l2); - out.Write(&l2, size); - return true; -} - -bool Cfxp::WriteLE(CFile &out, const float &f) -{ - int size=sizeof(float); - float f2 = f; - if (NeedSwap()) - SwapBytes(f2); - out.Write(&f2, size); - return true; -} - -bool Cfxp::WriteLE(CFile &out, const char *c, UINT length) -{ - int size=sizeof(char)*length; - out.Write(c, size); - return true; -} - -bool Cfxp::NeedSwap() -//------------------- -{ - if (m_bNeedSwap < 0) //don't yet know if we need to swap - find out! - { - static char szChnk[] = "CcnK"; - static long lChnk = 'CcnK'; - m_bNeedSwap = !!memcmp(szChnk, &lChnk, 4); - } - - return m_bNeedSwap != 0; -} - - -void Cfxp::SwapBytes(long &l) -//--------------------------- -{ - unsigned char *b = (unsigned char *)&l; - long intermediate = ((long)b[0] << 24) | ((long)b[1] << 16) | ((long)b[2] << 8) | (long)b[3]; - l = intermediate; - -} - -void Cfxp::SwapBytes(float &f) -//---------------------------- -{ - long *pl = (long *)&f; - SwapBytes(*pl); -} Deleted: trunk/OpenMPT/mptrack/fxp.h =================================================================== --- trunk/OpenMPT/mptrack/fxp.h 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/fxp.h 2013-02-15 16:01:20 UTC (rev 1527) @@ -1,42 +0,0 @@ -#pragma once -//See vstfxstore.h in VST SDK2.3 for an overview of the fxp file structure. - -class Cfxp -{ -public: - Cfxp(void); - Cfxp(CString fileName); - Cfxp(long fxID, long fxVersion, long numParams, float *params); - Cfxp(long ID, long version, long nPrograms, long inChunkSize, void *inChunk); - ~Cfxp(void); - - long ChunkMagic; // "CcnK" - long byteSize; // size of this chunk, excluding ChunkMagic and byteSize - long fxMagic; // "FxCk" - long version; // VST version - ignore - long fxID; // Plugin unique ID - long fxVersion; // plugin version - ignore? - - long numParams; - char prgName[30]; - float *params; - long chunkSize; - void *chunk; - - bool Save(CString fileName); - -protected: - int m_bNeedSwap; - bool Load(CString fileName); - - bool ReadLE(CFile &in, long &l); - bool ReadLE(CFile &in, float &f); - bool ReadLE(CFile &in, char *c, UINT length=1); - bool WriteLE(CFile &out, const long &l); - bool WriteLE(CFile &out, const float &f); - bool WriteLE(CFile &out, const char *c, UINT length=1); - - bool NeedSwap(); - void SwapBytes(long &l); - void SwapBytes(float &f); -}; Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-02-15 16:01:20 UTC (rev 1527) @@ -325,7 +325,7 @@ > </File> <File - RelativePath=".\fxp.cpp" + RelativePath=".\VstPresets.cpp" > </File> <File @@ -883,7 +883,7 @@ > </File> <File - RelativePath=".\fxp.h" + RelativePath=".\VstPresets.h" > </File> <File Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-02-15 16:01:20 UTC (rev 1527) @@ -210,7 +210,6 @@ <ClCompile Include="EffectVis.cpp" /> <ClCompile Include="..\soundlib\Fastmix.cpp" /> <ClCompile Include="ExceptionHandler.cpp" /> - <ClCompile Include="fxp.cpp" /> <ClCompile Include="globals.cpp" /> <ClCompile Include="HyperEdit.cpp" /> <ClCompile Include="HyperEdit2.cpp" /> @@ -316,6 +315,7 @@ <ClCompile Include="..\Soundlib\Load_umx.cpp" /> <ClCompile Include="..\soundlib\Load_wav.cpp" /> <ClCompile Include="..\soundlib\Load_xm.cpp" /> + <ClCompile Include="VstPresets.cpp" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="mptrack.rc" /> @@ -373,7 +373,6 @@ <ClInclude Include="..\Soundlib\Dlsbank.h" /> <ClInclude Include="EffectVis.h" /> <ClInclude Include="..\soundlib\Endianness.h" /> - <ClInclude Include="fxp.h" /> <ClInclude Include="globals.h" /> <ClInclude Include="InputHandler.h" /> <ClInclude Include="KeyConfigDlg.h" /> @@ -430,6 +429,7 @@ <ClInclude Include="tuningRatioMapWnd.h" /> <ClInclude Include="test\test.h" /> <ClInclude Include="..\soundlib\Loaders.h" /> + <ClInclude Include="VstPresets.h" /> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-02-15 16:01:20 UTC (rev 1527) @@ -127,9 +127,6 @@ <ClCompile Include="draw_pat.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="fxp.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="..\soundlib\Fastmix.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -424,6 +421,9 @@ <ClCompile Include="..\soundlib\MixerSettings.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="VstPresets.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -468,9 +468,6 @@ <ClInclude Include="..\Soundlib\Dlsbank.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="fxp.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\soundlib\Endianness.h"> <Filter>Header Files</Filter> </ClInclude> @@ -753,6 +750,9 @@ <ClInclude Include="..\soundlib\MixerSettings.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="VstPresets.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/soundlib/plugins/JBridge.cpp =================================================================== --- trunk/OpenMPT/soundlib/plugins/JBridge.cpp 2013-02-14 18:33:07 UTC (rev 1526) +++ trunk/OpenMPT/soundlib/plugins/JBridge.cpp 2013-02-15 16:01:20 UTC (rev 1527) @@ -10,14 +10,15 @@ #include "stdafx.h" + #include <pluginterfaces/vst2.x/aeffectx.h> #include "JBridge.h" +#ifdef ENABLE_JBRIDGE + namespace JBridge { -#ifdef ENABLE_JBRIDGE - // Name of the proxy DLL to load static const char *proxyRegKey = "Software\\JBridge"; @@ -106,6 +107,6 @@ return pfnBridgeMain(audioMaster, pluginPath); } +} + #endif // ENABLE_JBRIDGE - -} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-15 17:24:42
|
Revision: 1528 http://sourceforge.net/p/modplug/code/1528 Author: saga-games Date: 2013-02-15 17:24:31 +0000 (Fri, 15 Feb 2013) Log Message: ----------- [Ref] Endianness handling improvements and fixes. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/soundlib/Endianness.h trunk/OpenMPT/soundlib/ITTools.h trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Wav.h Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-02-15 16:01:20 UTC (rev 1527) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-02-15 17:24:31 UTC (rev 1528) @@ -926,28 +926,28 @@ if(m_pSndFile->m_PatternCuePoints.size() > 0) { // Cue point header - WAVCUEHEADER cuehdr; - cuehdr.cue_id = LittleEndian(IFFID_cue); - cuehdr.cue_num = m_pSndFile->m_PatternCuePoints.size(); - cuehdr.cue_len = 4 + cuehdr.cue_num * sizeof(WAVCUEPOINT); - cuePointLength = 8 + cuehdr.cue_len; - cuehdr.cue_num = LittleEndian(cuehdr.cue_num); - cuehdr.cue_len = LittleEndian(cuehdr.cue_len); - fwrite(&cuehdr, 1, sizeof(WAVCUEHEADER), f); + WavCueHeader cuehdr; + cuehdr.id = IFFID_cue; + cuehdr.numPoints = m_pSndFile->m_PatternCuePoints.size(); + cuehdr.length = 4 + cuehdr.numPoints * sizeof(WavCuePoint); + cuePointLength = 8 + cuehdr.length; + cuehdr.ConvertEndianness(); + fwrite(&cuehdr, 1, sizeof(WavCueHeader), f); // Write all cue points vector<PatternCuePoint>::const_iterator iter; DWORD num = 0; for(iter = m_pSndFile->m_PatternCuePoints.begin(); iter != m_pSndFile->m_PatternCuePoints.end(); ++iter, num++) { - WAVCUEPOINT cuepoint; - cuepoint.cp_id = LittleEndian(num); - cuepoint.cp_pos = LittleEndian((DWORD)iter->offset); - cuepoint.cp_chunkid = LittleEndian(IFFID_data); - cuepoint.cp_chunkstart = 0; // we use no Wave List Chunk (wavl) as we have only one data block, so this should be 0. - cuepoint.cp_blockstart = 0; // dito - cuepoint.cp_offset = LittleEndian((DWORD)iter->offset); - fwrite(&cuepoint, 1, sizeof(WAVCUEPOINT), f); + WavCuePoint cuepoint; + cuepoint.id = num; + cuepoint.pos = (uint32)iter->offset; + cuepoint.chunkID = IFFID_data; + cuepoint.chunkStart = 0; // we use no Wave List Chunk (wavl) as we have only one data block, so this should be 0. + cuepoint.blockStart = 0; // dito + cuepoint.offset = (uint32)iter->offset; + cuepoint.ConvertEndianness(); + fwrite(&cuepoint, 1, sizeof(WavCuePoint), f); } m_pSndFile->m_PatternCuePoints.clear(); } Modified: trunk/OpenMPT/soundlib/Endianness.h =================================================================== --- trunk/OpenMPT/soundlib/Endianness.h 2013-02-15 16:01:20 UTC (rev 1527) +++ trunk/OpenMPT/soundlib/Endianness.h 2013-02-15 17:24:31 UTC (rev 1528) @@ -19,17 +19,38 @@ // endian architecture or value x in format of current architecture to little endian // format. +#if defined(__GNUC__) && __GNUC__ >= 4 && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3) +// This only works with version 4.3 and greater. +// GCC IS +#define bswap32 __builtin_bswap32 + +#elif defined(_MSC_VER) +// VC++ IS +#include <intrin.h> +#define bswap16 _byteswap_ushort +#define bswap32 _byteswap_ulong + +#endif + +// No intrinsics available +#ifndef bswap16 +#define bswap16(x) (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)) +#endif +#ifndef bswap32 +#define bswap32(x) (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | ((x & 0xFF000000) >> 24)) +#endif + // Deprecated. Use "SwapBytesXX" versions below. #ifdef PLATFORM_BIG_ENDIAN // PPC -inline uint32 LittleEndian(uint32 x) { return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | ((x & 0xFF000000) >> 24); } -inline uint16 LittleEndianW(uint16 x) { return (uint16)(((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); } +inline uint32 LittleEndian(uint32 x) { return bswap32(x); } +inline uint16 LittleEndianW(uint16 x) { return bswap16(x); } #define BigEndian(x) (x) #define BigEndianW(x) (x) #else // x86 -inline uint32 BigEndian(uint32 x) { return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | ((x & 0xFF000000) >> 24); } -inline uint16 BigEndianW(uint16 x) { return (uint16)(((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); } +inline uint32 BigEndian(uint32 x) { return bswap32(x); } +inline uint16 BigEndianW(uint16 x) { return bswap16(x); } #define LittleEndian(x) (x) #define LittleEndianW(x) (x) #endif @@ -39,21 +60,23 @@ // PPC inline uint32 SwapBytesBE(uint32 &value) { return value; } inline uint16 SwapBytesBE(uint16 &value) { return value; } -inline uint32 SwapBytesLE(uint32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } -inline uint16 SwapBytesLE(uint16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00)); } +inline uint32 SwapBytesLE(uint32 &value) { return value = bswap32(value); } +inline uint16 SwapBytesLE(uint16 &value) { return value = bswap16(value); } inline int32 SwapBytesBE(int32 &value) { return value; } inline int16 SwapBytesBE(int16 &value) { return value; } -inline int32 SwapBytesLE(int32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } -inline int16 SwapBytesLE(int16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00))); } +inline int32 SwapBytesLE(int32 &value) { return value = bswap32(value); } +inline int16 SwapBytesLE(int16 &value) { return value = bswap16(value); } #else // x86 -inline uint32 SwapBytesBE(uint32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } -inline uint16 SwapBytesBE(uint16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00))); } +inline uint32 SwapBytesBE(uint32 &value) { return value = bswap32(value); } +inline uint16 SwapBytesBE(uint16 &value) { return value = bswap16(value); } inline uint32 SwapBytesLE(uint32 &value) { return value; } inline uint16 SwapBytesLE(uint16 &value) { return value; } -inline int32 SwapBytesBE(int32 &value) { return (value = ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24)); } -inline int16 SwapBytesBE(int16 &value) { return (value = (((value >> 8) & 0xFF) | ((value << 8) & 0xFF00))); } +inline int32 SwapBytesBE(int32 &value) { return value = bswap32(value); } +inline int16 SwapBytesBE(int16 &value) { return value = bswap16(value); } inline int32 SwapBytesLE(int32 &value) { return value; } inline int16 SwapBytesLE(int16 &value) { return value; } #endif +#undef bswap16 +#undef bswap32 \ No newline at end of file Modified: trunk/OpenMPT/soundlib/ITTools.h =================================================================== --- trunk/OpenMPT/soundlib/ITTools.h 2013-02-15 16:01:20 UTC (rev 1527) +++ trunk/OpenMPT/soundlib/ITTools.h 2013-02-15 17:24:31 UTC (rev 1528) @@ -333,13 +333,6 @@ #pragma pack(pop) -// MPT stuff -enum MPTHackMagic -{ - magicPatternNames = 0x4D414E50, // "PNAM" pattern names - magicChannelNames = 0x4D414E43, // "CNAM" channel names -}; - enum IT_ReaderBitMasks { // pattern row parsing, the channel data is read to obtain Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2013-02-15 16:01:20 UTC (rev 1527) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2013-02-15 17:24:31 UTC (rev 1528) @@ -1204,10 +1204,11 @@ // Writing pattern names if(numNamedPats) { - DWORD d = LittleEndian(magicPatternNames); // "PNAM" - fwrite(&d, 1, 4, f); - d = numNamedPats * MAX_PATTERNNAME; - fwrite(&d, 1, 4, f); + char magic[4]; + memcpy(magic, "PNAM", 4); + fwrite(magic, 4, 1, f); + uint32 d = numNamedPats * MAX_PATTERNNAME; + fwrite(&d, 4, 1, f); for(PATTERNINDEX nPat = 0; nPat < numNamedPats; nPat++) { @@ -1221,8 +1222,9 @@ // Writing channel names if(dwChnNamLen && !compatibilityExport) { - DWORD d = LittleEndian(magicChannelNames); // "CNAM" - fwrite(&d, 1, 4, f); + char magic[4]; + memcpy(magic, "CNAM", 4); + fwrite(magic, 4, 1, f); fwrite(&dwChnNamLen, 1, 4, f); UINT nChnNames = dwChnNamLen / MAX_CHANNELNAME; for(UINT inam = 0; inam < nChnNames; inam++) Modified: trunk/OpenMPT/soundlib/Load_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2013-02-15 16:01:20 UTC (rev 1527) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2013-02-15 17:24:31 UTC (rev 1528) @@ -178,10 +178,10 @@ { SAMPLEINDEX realSample = static_cast<SAMPLEINDEX>(file.ReadUint32LE()); ITSample sampleHeader; - file.Read(sampleHeader); + file.ReadConvertEndianness(sampleHeader); size = file.ReadUint32LE(); - if(realSample >= 1 && realSample < MAX_SAMPLES && sampleHeader.id == LittleEndian(ITSample::magic)) + if(realSample >= 1 && realSample < MAX_SAMPLES && sampleHeader.id == ITSample::magic) { sampleHeader.ConvertToMPT(Samples[realSample]); StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[realSample], sampleHeader.name); @@ -457,6 +457,7 @@ fwrite(&id, 1, sizeof(id), f); itss.samplepointer = 0; + itss.ConvertEndianness(); fwrite(&itss, 1, sizeof(itss), f); id = Samples[nsmp].GetSampleSizeInBytes(); Modified: trunk/OpenMPT/soundlib/Wav.h =================================================================== --- trunk/OpenMPT/soundlib/Wav.h 2013-02-15 16:01:20 UTC (rev 1527) +++ trunk/OpenMPT/soundlib/Wav.h 2013-02-15 17:24:31 UTC (rev 1528) @@ -148,23 +148,42 @@ } WAVEEXTRAHEADER; -typedef struct WAVCUEHEADER +struct WavCueHeader { - DWORD cue_id; // "cue " -> 0x20657563 - DWORD cue_len; - DWORD cue_num; -} WAVCUEHEADER; + uint32 id; // "cue " -> 0x20657563 + uint32 length; + uint32 numPoints; + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(id); + SwapBytesLE(length); + SwapBytesLE(numPoints); + } +}; -typedef struct WAVCUEPOINT + +struct WavCuePoint { - DWORD cp_id; // Unique identification value - DWORD cp_pos; // Play order position - DWORD cp_chunkid; // RIFF ID of corresponding data chunk - DWORD cp_chunkstart; // Byte Offset of Data Chunk - DWORD cp_blockstart; // Byte Offset to sample of First Channel - DWORD cp_offset; // Byte Offset to sample byte of First Channel -} WAVCUEPOINT; + uint32 id; // Unique identification value + uint32 pos; // Play order position + uint32 chunkID; // RIFF ID of corresponding data chunk + uint32 chunkStart; // Byte Offset of Data Chunk + uint32 blockStart; // Byte Offset to sample of First Channel + uint32 offset; // Byte Offset to sample byte of First Channel + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(id); + SwapBytesLE(pos); + SwapBytesLE(chunkID); + SwapBytesLE(chunkStart); + SwapBytesLE(blockStart); + SwapBytesLE(offset); + } +}; + #pragma pack(pop) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-16 01:12:39
|
Revision: 1531 http://sourceforge.net/p/modplug/code/1531 Author: saga-games Date: 2013-02-16 01:12:24 +0000 (Sat, 16 Feb 2013) Log Message: ----------- [Fix] Previewing samples from treeview only worked about every other time. [Fix] fbx -> fxb typo [Mod] OpenMPT: Version is now 1.21.01.13 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/mptrack/AbstractVstEditor.cpp trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/soundlib/Sndfile.cpp Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-02-15 17:54:10 UTC (rev 1530) +++ trunk/OpenMPT/common/version.h 2013-02-16 01:12:24 UTC (rev 1531) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 12 +#define VER_MINORMINOR 13 //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/AbstractVstEditor.cpp =================================================================== --- trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2013-02-15 17:54:10 UTC (rev 1530) +++ trunk/OpenMPT/mptrack/AbstractVstEditor.cpp 2013-02-16 01:12:24 UTC (rev 1531) @@ -104,7 +104,7 @@ if(!m_pVstPlugin) return; FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(true, "fxp", "", - "VST Plugin Programs and Banks (*.fxp,*.fbx)|*.fxp;*.fxb|" + "VST Plugin Programs and Banks (*.fxp,*.fxb)|*.fxp;*.fxb|" "VST Plugin Programs (*.fxp)|*.fxp|" "VST Plugin Banks (*.fxb)|*.fxb|" "All Files|*.*||", @@ -118,6 +118,7 @@ { if(m_pVstPlugin->GetModDoc() != nullptr) m_pVstPlugin->GetModDoc()->SetModified(); + UpdatePresetMenu(true); UpdatePresetField(); } else { @@ -158,7 +159,7 @@ void CAbstractVstEditor::SetupMenu(bool force) -//---------------------------------- +//-------------------------------------------- { //TODO: create menus on click so they are only updated when required if (m_pVstPlugin) Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2013-02-15 17:54:10 UTC (rev 1530) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2013-02-16 01:12:24 UTC (rev 1531) @@ -1034,7 +1034,7 @@ } FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(true, "fxp", "", - "VST Plugin Programs and Banks (*.fxp,*.fbx)|*.fxp;*.fxb|" + "VST Plugin Programs and Banks (*.fxp,*.fxb)|*.fxp;*.fxb|" "VST Plugin Programs (*.fxp)|*.fxp|" "VST Plugin Banks (*.fxb)|*.fxb|" "All Files|*.*||", @@ -1046,7 +1046,7 @@ { if(pSndFile->GetModSpecifications().supportsPlugins) pModDoc->SetModified(); - } else + } else { Reporting::Error(retVal, "Plugin Preset"); } Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-15 17:54:10 UTC (rev 1530) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-16 01:12:24 UTC (rev 1531) @@ -724,6 +724,7 @@ m_nRow = 0; RecalculateSamplesPerTick(); + visitedSongRows.Initialize(true); if ((m_nRestartPos >= Order.size()) || (Order[m_nRestartPos] >= Patterns.Size())) m_nRestartPos = 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-16 15:06:59
|
Revision: 1532 http://sourceforge.net/p/modplug/code/1532 Author: saga-games Date: 2013-02-16 15:06:45 +0000 (Sat, 16 Feb 2013) Log Message: ----------- [Imp] OpenMPT doesn't request exclusive file reading rights anymore, so it is now possible to open files that are being read by another application at the same time (http://bugs.openmpt.org/view.php?id=352). [Ref] Rewrote IMF loader to use the FileReader class. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mptrack.cpp trunk/OpenMPT/soundlib/Load_imf.cpp trunk/OpenMPT/soundlib/ModSequence.cpp trunk/OpenMPT/soundlib/ModSequence.h trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/patternContainer.cpp Modified: trunk/OpenMPT/mptrack/Mptrack.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -1629,6 +1629,8 @@ "http://zlib.net/|" "Josh Coalson for libFLAC|" "http://flac.sourceforge.net/|" + "The mpg123 project for libmpg123|" + "http://mpg123.de/|" "Storlek for all the IT compatibility hints and testcases|" "as well as the IMF, OKT and ULT loaders|" "http://schismtracker.org/|" @@ -2101,7 +2103,7 @@ BOOL CMappedFile::Open(LPCSTR lpszFileName) //----------------------------------------- { - return m_File.Open(lpszFileName, CFile::modeRead|CFile::typeBinary); + return m_File.Open(lpszFileName, CFile::modeRead | CFile::typeBinary | CFile::shareDenyWrite); } Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -17,85 +17,216 @@ #pragma pack(push, 1) -struct IMFCHANNEL +struct IMFChannel { - char name[12]; // Channel name (ASCIIZ-String, max 11 chars) + char name[12]; // Channel name (ASCIIZ-String, max 11 chars) uint8 chorus; // Default chorus uint8 reverb; // Default reverb uint8 panning; // Pan positions 00-FF uint8 status; // Channel status: 0 = enabled, 1 = mute, 2 = disabled (ignore effects!) }; -struct IMFHEADER +struct IMFFileHeader { - char title[32]; // Songname (ASCIIZ-String, max. 31 chars) - uint16 ordnum; // Number of orders saved - uint16 patnum; // Number of patterns saved - uint16 insnum; // Number of instruments saved - uint16 flags; // Module flags (&1 => linear) - uint8 unused1[8]; - uint8 tempo; // Default tempo (Axx, 1..255) - uint8 bpm; // Default beats per minute (BPM) (Txx, 32..255) - uint8 master; // Default mastervolume (Vxx, 0..64) - uint8 amp; // Amplification factor (mixing volume, 4..127) - uint8 unused2[8]; - char im10[4]; // 'IM10' - IMFCHANNEL channels[32]; // Channel settings + enum SongFlags + { + lineSlides = 0x01, + }; + + char title[32]; // Songname (ASCIIZ-String, max. 31 chars) + uint16 ordNum; // Number of orders saved + uint16 patNum; // Number of patterns saved + uint16 insNum; // Number of instruments saved + uint16 flags; // See SongFlags + uint8 unused1[8]; + uint8 tempo; // Default tempo (Axx, 1...255) + uint8 bpm; // Default beats per minute (BPM) (Txx, 32...255) + uint8 master; // Default master volume (Vxx, 0...64) + uint8 amp; // Amplification factor (mixing volume, 4...127) + uint8 unused2[8]; + char im10[4]; // 'IM10' + IMFChannel channels[32]; // Channel settings uint8 orderlist[256]; // Order list (0xFF = +++; blank out anything beyond ordnum) + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(ordNum); + SwapBytesLE(patNum); + SwapBytesLE(insNum); + SwapBytesLE(flags); + } }; -enum +struct IMFEnvelope { - IMF_ENV_VOL = 0, - IMF_ENV_PAN = 1, - IMF_ENV_FILTER = 2, -}; + enum EnvFlags + { + envEnabled = 0x01, + envSustain = 0x02, + envLoop = 0x04, + }; -struct IMFENVELOPE -{ uint8 points; // Number of envelope points uint8 sustain; // Envelope sustain point uint8 loop_start; // Envelope loop start point uint8 loop_end; // Envelope loop end point - uint8 flags; // Envelope flags + uint8 flags; // See EnvFlags uint8 unused[3]; }; -struct IMFENVNODES +struct IMFEnvNode { uint16 tick; uint16 value; }; -struct IMFINSTRUMENT +struct IMFInstrument { - char name[32]; // Inst. name (ASCIIZ-String, max. 31 chars) + enum EnvTypes + { + volEnv = 0, + panEnv = 1, + filterEnv = 2, + }; + + char name[32]; // Inst. name (ASCIIZ-String, max. 31 chars) uint8 map[120]; // Multisample settings uint8 unused[8]; - IMFENVNODES nodes[3][16]; - IMFENVELOPE env[3]; + IMFEnvNode nodes[3][16]; + IMFEnvelope env[3]; uint16 fadeout; // Fadeout rate (0...0FFFH) - uint16 smpnum; // Number of samples in instrument - char ii10[4]; // 'II10' + uint16 smpNum; // Number of samples in instrument + char ii10[4]; // 'II10' + + void ConvertEnvelope(InstrumentEnvelope &mptEnv, EnvTypes e) const + { + const int shift = (e == volEnv) ? 0 : 2; + + mptEnv.dwFlags.set(ENV_ENABLED, (env[e].flags & 1) != 0); + mptEnv.dwFlags.set(ENV_SUSTAIN, (env[e].flags & 2) != 0); + mptEnv.dwFlags.set(ENV_LOOP, (env[e].flags & 4) != 0); + + mptEnv.nNodes = env[e].points; + Limit(mptEnv.nNodes, 2u, 16u); + mptEnv.nLoopStart = env[e].loop_start; + mptEnv.nLoopEnd = env[e].loop_end; + mptEnv.nSustainStart = mptEnv.nSustainEnd = env[e].sustain; + + uint16 minTick = 0; // minimum tick value for next node + for(uint32 n = 0; n < mptEnv.nNodes; n++) + { + minTick = mptEnv.Ticks[n] = Util::Max(minTick, nodes[e][n].tick); + minTick++; + mptEnv.Values[n] = static_cast<uint8>(Util::Min(nodes[e][n].value >> shift, ENVELOPE_MAX)); + } + } + + // Convert an IMFInstrument to OpenMPT's internal instrument representation. + void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX firstSample) const + { + StringFixer::ReadString<StringFixer::nullTerminated>(mptIns.name, name); + + if(smpNum) + { + STATIC_ASSERT(CountOf(mptIns.Keyboard) >= CountOf(map)); + for(size_t note = 0; note < CountOf(map); note++) + { + mptIns.Keyboard[note] = firstSample + map[note]; + } + } + + mptIns.nFadeOut = fadeout; + + ConvertEnvelope(mptIns.VolEnv, volEnv); + ConvertEnvelope(mptIns.PanEnv, panEnv); + ConvertEnvelope(mptIns.PitchEnv, filterEnv); + if(mptIns.PitchEnv.dwFlags[ENV_ENABLED]) + mptIns.PitchEnv.dwFlags.set(ENV_FILTER); + + // hack to get === to stop notes (from modplug's xm loader) + if(!mptIns.VolEnv.dwFlags[ENV_ENABLED] && !mptIns.nFadeOut) + mptIns.nFadeOut = 8192; + } + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + for(size_t e = 0; e < CountOf(nodes); e++) + { + for(size_t n = 0; n < CountOf(nodes[0]); n++) + { + SwapBytesLE(nodes[e][n].tick); + SwapBytesLE(nodes[e][n].value); + } + } + SwapBytesLE(fadeout); + SwapBytesLE(smpNum); + } }; -struct IMFSAMPLE +struct IMFSample { - char filename[13]; // Sample filename (12345678.ABC) */ - uint8 unused1[3]; - uint32 length; // Length (in bytes) - uint32 loop_start; // Loop start (in bytes) - uint32 loop_end; // Loop end (in bytes) - uint32 C5Speed; // Samplerate - uint8 volume; // Default volume (0...64) - uint8 panning; // Default pan (0...255) - uint8 unused2[14]; - uint8 flags; // Sample flags - uint8 unused3[5]; - uint16 ems; // Reserved for internal usage - uint32 dram; // Reserved for internal usage - char is10[4]; // 'IS10' + enum SampleFlags + { + smpLoop = 0x01, + smpPingPongLoop = 0x02, + smp16Bit = 0x04, + smpPanning = 0x08, + }; + + char filename[13]; // Sample filename (12345678.ABC) */ + uint8 unused1[3]; + uint32 length; // Length (in bytes) + uint32 loopStart; // Loop start (in bytes) + uint32 loopEnd; // Loop end (in bytes) + uint32 c5Speed; // Samplerate + uint8 volume; // Default volume (0...64) + uint8 panning; // Default pan (0...255) + uint8 unused2[14]; + uint8 flags; // Sample flags + uint8 unused3[5]; + uint16 ems; // Reserved for internal usage + uint32 dram; // Reserved for internal usage + char is10[4]; // 'IS10' + + // Convert an IMFSample to OpenMPT's internal sample representation. + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + StringFixer::ReadString<StringFixer::nullTerminated>(mptSmp.filename, filename); + + mptSmp.nLength = length; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd; + mptSmp.nC5Speed = c5Speed; + mptSmp.nVolume = volume * 4; + mptSmp.nPan = panning; + if(flags & smpLoop) + mptSmp.uFlags.set(CHN_LOOP); + if(flags & smpPingPongLoop) + mptSmp.uFlags.set(CHN_PINGPONGLOOP); + if(flags & smp16Bit) + { + mptSmp.uFlags.set(CHN_16BIT); + mptSmp.nLength /= 2; + mptSmp.nLoopStart /= 2; + mptSmp.nLoopEnd /= 2; + } + if(flags & smpPanning) + mptSmp.uFlags.set(CHN_PANNING); + } + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(length); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(c5Speed); + } }; + #pragma pack(pop) static const uint8 imfEffects[] = @@ -148,47 +279,47 @@ CMD_NONE, // 0x23 Zxx Reverb - XXX }; -static void ImportIMFEffect(ModCommand *note) -//------------------------------------------- +static void ImportIMFEffect(ModCommand &m) +//---------------------------------------- { uint8 n; // fix some of them - switch (note->command) + switch (m.command) { case 0xE: // fine volslide // hackaround to get almost-right behavior for fine slides (i think!) - if(note->param == 0) + if(m.param == 0) /* nothing */; - else if(note->param == 0xF0) - note->param = 0xEF; - else if(note->param == 0x0F) - note->param = 0xFE; - else if(note->param & 0xF0) - note->param |= 0x0F; + else if(m.param == 0xF0) + m.param = 0xEF; + else if(m.param == 0x0F) + m.param = 0xFE; + else if(m.param & 0xF0) + m.param |= 0x0F; else - note->param |= 0xF0; + m.param |= 0xF0; break; case 0xF: // set finetune // we don't implement this, but let's at least import the value - note->param = 0x20 | min(note->param >> 4, 0xf); + m.param = 0x20 | min(m.param >> 4, 0x0F); break; case 0x14: // fine slide up case 0x15: // fine slide down // this is about as close as we can do... - if(note->param >> 4) - note->param = 0xf0 | min(note->param >> 4, 0xf); + if(m.param >> 4) + m.param = 0xF0 | min(m.param >> 4, 0x0F); else - note->param |= 0xe0; + m.param |= 0xE0; break; case 0x16: // cutoff - note->param >>= 1; + m.param >>= 1; break; case 0x1F: // set global volume - note->param = min(note->param << 1, 0xff); + m.param = min(m.param << 1, 0xFF); break; case 0x21: n = 0; - switch (note->param >> 4) + switch (m.param >> 4) { case 0: /* undefined, but since S0x does nothing in IT anyway, we won't care. @@ -198,7 +329,7 @@ default: // undefined case 0x1: // set filter case 0xF: // invert loop - note->command = CMD_NONE; + m.command = CMD_NONE; break; case 0x3: // glissando n = 0x20; @@ -223,111 +354,62 @@ /* predicament: we can only disable one envelope at a time. volume is probably most noticeable, so let's go with that. (... actually, orpheus doesn't even seem to implement this at all) */ - note->param = 0x77; + m.param = 0x77; break; case 0x18: // sample offset // O00 doesn't pick up the previous value - if(!note->param) - note->command = CMD_NONE; + if(!m.param) + m.command = CMD_NONE; break; } if(n) - note->param = n | (note->param & 0x0F); + m.param = n | (m.param & 0x0F); break; } - note->command = (note->command < CountOf(imfEffects)) ? imfEffects[note->command] : CMD_NONE; - if(note->command == CMD_VOLUME && note->volcmd == VOLCMD_NONE) + m.command = (m.command < CountOf(imfEffects)) ? imfEffects[m.command] : CMD_NONE; + if(m.command == CMD_VOLUME && m.volcmd == VOLCMD_NONE) { - note->volcmd = VOLCMD_VOLUME; - note->vol = note->param; - note->command = CMD_NONE; - note->param = 0; + m.volcmd = VOLCMD_VOLUME; + m.vol = m.param; + m.command = CMD_NONE; + m.param = 0; } } -static void LoadIMFEnvelope(InstrumentEnvelope *env, const IMFINSTRUMENT *imfins, const int e) -//-------------------------------------------------------------------------------------------- +bool CSoundFile::ReadIMF(FileReader &file) +//---------------------------------------- { - const int shift = (e == IMF_ENV_VOL) ? 0 : 2; - - env->dwFlags.set(ENV_ENABLED, (imfins->env[e].flags & 1) != 0); - env->dwFlags.set(ENV_SUSTAIN, (imfins->env[e].flags & 2) != 0); - env->dwFlags.set(ENV_LOOP, (imfins->env[e].flags & 4) != 0); - - env->nNodes = imfins->env[e].points; - Limit(env->nNodes, 2u, 16u); - env->nLoopStart = imfins->env[e].loop_start; - env->nLoopEnd = imfins->env[e].loop_end; - env->nSustainStart = env->nSustainEnd = imfins->env[e].sustain; - - uint16 min = 0; // minimum tick value for next node - for(uint32 n = 0; n < env->nNodes; n++) + IMFFileHeader fileHeader; + file.Rewind(); + if(!file.ReadConvertEndianness(fileHeader) + || memcmp(fileHeader.im10, "IM10", 4)) { - uint16 nTick, nValue; - nTick = LittleEndianW(imfins->nodes[e][n].tick); - nValue = LittleEndianW(imfins->nodes[e][n].value) >> shift; - env->Ticks[n] = (uint16)max(min, nTick); - env->Values[n] = (uint8)min(nValue, ENVELOPE_MAX); - min = nTick + 1; + return false; } -} -bool CSoundFile::ReadIMF(const LPCBYTE lpStream, const DWORD dwMemLength) -//----------------------------------------------------------------------- -{ - DWORD dwMemPos = 0; + // Read channel configuration vector<bool> ignoreChannels(32, false); // bit set for each channel that's completely disabled - - ASSERT_CAN_READ(sizeof(IMFHEADER)); - IMFHEADER hdr; - memcpy(&hdr, lpStream, sizeof(IMFHEADER)); - dwMemPos = sizeof(IMFHEADER); - - hdr.ordnum = LittleEndianW(hdr.ordnum); - hdr.patnum = LittleEndianW(hdr.patnum); - hdr.insnum = LittleEndianW(hdr.insnum); - hdr.flags = LittleEndianW(hdr.flags); - - if(memcmp(hdr.im10, "IM10", 4) != 0) - return false; - - m_nType = MOD_TYPE_IMF; - SetModFlag(MSF_COMPATIBLE_PLAY, true); - - // song name - MemsetZero(m_szNames); - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], hdr.title); - - m_SongFlags = (hdr.flags & 1) ? SONG_LINEARSLIDES : SongFlags(0); - m_nDefaultSpeed = hdr.tempo; - m_nDefaultTempo = hdr.bpm; - m_nDefaultGlobalVolume = CLAMP(hdr.master, 0, 64) << 2; - m_nSamplePreAmp = CLAMP(hdr.amp, 4, 127); - - m_nSamples = 0; // Will be incremented later - m_nInstruments = 0; - m_nChannels = 0; - for(CHANNELINDEX nChn = 0; nChn < 32; nChn++) + for(CHANNELINDEX chn = 0; chn < 32; chn++) { - ChnSettings[nChn].nPan = hdr.channels[nChn].panning * 64 / 255; - ChnSettings[nChn].nPan *= 4; + ChnSettings[chn].Reset(); + ChnSettings[chn].nPan = fileHeader.channels[chn].panning * 256 / 255; - StringFixer::ReadString<StringFixer::nullTerminated>(ChnSettings[nChn].szName, hdr.channels[nChn].name); + StringFixer::ReadString<StringFixer::nullTerminated>(ChnSettings[chn].szName, fileHeader.channels[chn].name); // TODO: reverb/chorus? - switch(hdr.channels[nChn].status) + switch(fileHeader.channels[chn].status) { case 0: // enabled; don't worry about it - m_nChannels = nChn + 1; + m_nChannels = chn + 1; break; case 1: // mute - ChnSettings[nChn].dwFlags = CHN_MUTE; - m_nChannels = nChn + 1; + ChnSettings[chn].dwFlags = CHN_MUTE; + m_nChannels = chn + 1; break; case 2: // disabled - ChnSettings[nChn].dwFlags = CHN_MUTE; - ignoreChannels[nChn] = true; + ChnSettings[chn].dwFlags = CHN_MUTE; + ignoreChannels[chn] = true; break; default: // uhhhh.... freak out //fprintf(stderr, "imf: channel %d has unknown status %d\n", n, hdr.channels[n].status); @@ -337,245 +419,179 @@ if(!m_nChannels) return false; //From mikmod: work around an Orpheus bug - if(hdr.channels[0].status == 0) + if(fileHeader.channels[0].status == 0) { - CHANNELINDEX nChn; - for(nChn = 1; nChn < 16; nChn++) - if(hdr.channels[nChn].status != 1) + CHANNELINDEX chn; + for(chn = 1; chn < 16; chn++) + if(fileHeader.channels[chn].status != 1) break; - if(nChn == 16) - for(nChn = 1; nChn < 16; nChn++) - ChnSettings[nChn].dwFlags.reset(CHN_MUTE); + if(chn == 16) + for(chn = 1; chn < 16; chn++) + ChnSettings[chn].dwFlags.reset(CHN_MUTE); } - Order.resize(hdr.ordnum); - for(ORDERINDEX nOrd = 0; nOrd < hdr.ordnum; nOrd++) - Order[nOrd] = ((hdr.orderlist[nOrd] == 0xFF) ? Order.GetIgnoreIndex() : (PATTERNINDEX)hdr.orderlist[nOrd]); + m_nType = MOD_TYPE_IMF; + SetModFlag(MSF_COMPATIBLE_PLAY, true); - // read patterns - for(PATTERNINDEX nPat = 0; nPat < hdr.patnum; nPat++) - { - uint16 length, nrows; - uint8 mask, channel; - int row; - unsigned int lostfx = 0; - ModCommand *note, junk_note; + // Song Name + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], fileHeader.title); - ASSERT_CAN_READ(4); - length = LittleEndianW(*((uint16 *)(lpStream + dwMemPos))); - nrows = LittleEndianW(*((uint16 *)(lpStream + dwMemPos + 2))); - dwMemPos += 4; + m_SongFlags = (fileHeader.flags & IMFFileHeader::lineSlides) ? SONG_LINEARSLIDES : SongFlags(0); + m_nDefaultSpeed = fileHeader.tempo; + m_nDefaultTempo = fileHeader.bpm; + m_nDefaultGlobalVolume = Clamp(fileHeader.master, uint8(0), uint8(64)) * 4; + m_nSamplePreAmp = Clamp(fileHeader.amp, uint8(4), uint8(127)); - if(Patterns.Insert(nPat, nrows)) - break; + m_nInstruments = fileHeader.insNum; + m_nSamples = 0; // Will be incremented later - row = 0; - while(row < nrows) + Order.resize(fileHeader.ordNum); + for(ORDERINDEX ord = 0; ord < fileHeader.ordNum; ord++) + Order[ord] = ((fileHeader.orderlist[ord] == 0xFF) ? Order.GetIgnoreIndex() : (PATTERNINDEX)fileHeader.orderlist[ord]); + + // Read patterns + for(PATTERNINDEX pat = 0; pat < fileHeader.patNum; pat++) + { + const uint16 length = file.ReadUint16LE(), numRows = file.ReadUint16LE(); + FileReader patternChunk = file.GetChunk(length - 4); + + if(Patterns.Insert(pat, numRows)) { - ASSERT_CAN_READ(1); - mask = *((uint8 *)(lpStream + dwMemPos)); - dwMemPos += 1; + continue; + } + + ModCommand junkNote; + ROWINDEX row = 0; + while(row < numRows) + { + uint8 mask = patternChunk.ReadUint8(); if(mask == 0) { row++; continue; } - channel = mask & 0x1F; + uint8 channel = mask & 0x1F; + ModCommand &m = ignoreChannels[channel] ? junkNote : *Patterns[pat].GetpModCommand(row, channel); - if(ignoreChannels[channel]) - { - /* should do this better, i.e. not go through the whole process of deciding - what to do with the effects since they're just being thrown out */ - //printf("disabled channel %d contains data\n", channel + 1); - note = &junk_note; - } else - { - note = Patterns[nPat].GetpModCommand(row, channel); - } - if(mask & 0x20) { - // read note/instrument - ASSERT_CAN_READ(2); - note->note = *((BYTE *)(lpStream + dwMemPos)); - note->instr = *((BYTE *)(lpStream + dwMemPos + 1)); - dwMemPos += 2; + // Read note/instrument + m.note = patternChunk.ReadUint8(); + m.instr = patternChunk.ReadUint8(); - if(note->note == 160) + if(m.note == 160) { - note->note = NOTE_KEYOFF; /* ??? */ - } else if(note->note == 255) + m.note = NOTE_KEYOFF; + } else if(m.note == 255) { - note->note = NOTE_NONE; /* ??? */ + m.note = NOTE_NONE; } else { - note->note = (note->note >> 4) * 12 + (note->note & 0x0F) + 12 + 1; - if(note->note > NOTE_MAX) + m.note = (m.note >> 4) * 12 + (m.note & 0x0F) + 12 + 1; + if(!m.IsNoteOrEmpty()) { - /*printf("%d.%d.%d: funny note 0x%02x\n", - nPat, row, channel, fp->data[fp->pos - 1]);*/ - note->note = NOTE_NONE; + m.note = NOTE_NONE; } } } - if((mask & 0xc0) == 0xC0) + if((mask & 0xC0) == 0xC0) { - // read both effects and figure out what to do with them - ASSERT_CAN_READ(4); - uint8 e1c = *((uint8 *)(lpStream + dwMemPos)); // Command 1 - uint8 e1d = *((uint8 *)(lpStream + dwMemPos + 1)); // Data 1 - uint8 e2c = *((uint8 *)(lpStream + dwMemPos + 2)); // Command 2 - uint8 e2d = *((uint8 *)(lpStream + dwMemPos + 3)); // Data 2 - dwMemPos += 4; + // Read both effects and figure out what to do with them + uint8 e1c = patternChunk.ReadUint8(); // Command 1 + uint8 e1d = patternChunk.ReadUint8(); // Data 1 + uint8 e2c = patternChunk.ReadUint8(); // Command 2 + uint8 e2d = patternChunk.ReadUint8(); // Data 2 if(e1c == 0x0C) { - note->vol = min(e1d, 0x40); - note->volcmd = VOLCMD_VOLUME; - note->command = e2c; - note->param = e2d; + m.vol = min(e1d, 0x40); + m.volcmd = VOLCMD_VOLUME; + m.command = e2c; + m.param = e2d; } else if(e2c == 0x0C) { - note->vol = min(e2d, 0x40); - note->volcmd = VOLCMD_VOLUME; - note->command = e1c; - note->param = e1d; + m.vol = min(e2d, 0x40); + m.volcmd = VOLCMD_VOLUME; + m.command = e1c; + m.param = e1d; } else if(e1c == 0x0A) { - note->vol = e1d * 64 / 255; - note->volcmd = VOLCMD_PANNING; - note->command = e2c; - note->param = e2d; + m.vol = e1d * 64 / 255; + m.volcmd = VOLCMD_PANNING; + m.command = e2c; + m.param = e2d; } else if(e2c == 0x0A) { - note->vol = e2d * 64 / 255; - note->volcmd = VOLCMD_PANNING; - note->command = e1c; - note->param = e1d; + m.vol = e2d * 64 / 255; + m.volcmd = VOLCMD_PANNING; + m.command = e1c; + m.param = e1d; } else { /* check if one of the effects is a 'global' effect -- if so, put it in some unused channel instead. otherwise pick the most important effect. */ - lostfx++; - note->command = e2c; - note->param = e2d; + m.command = e2c; + m.param = e2d; } } else if(mask & 0xC0) { - // there's one effect, just stick it in the effect column - ASSERT_CAN_READ(2); - note->command = *((BYTE *)(lpStream + dwMemPos)); - note->param = *((BYTE *)(lpStream + dwMemPos + 1)); - dwMemPos += 2; + // There's one effect, just stick it in the effect column + m.command = patternChunk.ReadUint8(); + m.param = patternChunk.ReadUint8(); } - if(note->command) - ImportIMFEffect(note); + if(m.command) + ImportIMFEffect(m); } } - SAMPLEINDEX firstsample = 1; // first sample index of the current instrument + SAMPLEINDEX firstSample = 1; // first sample index of the current instrument // read instruments - for(INSTRUMENTINDEX nIns = 0; nIns < hdr.insnum; nIns++) + for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++) { - IMFINSTRUMENT imfins; - ModInstrument *pIns; - ASSERT_CAN_READ(sizeof(IMFINSTRUMENT)); - memcpy(&imfins, lpStream + dwMemPos, sizeof(IMFINSTRUMENT)); - dwMemPos += sizeof(IMFINSTRUMENT); - m_nInstruments++; + ModInstrument *instr = AllocateInstrument(ins + 1); + IMFInstrument instrumentHeader; + if(!file.ReadConvertEndianness(instrumentHeader) || instr == nullptr) + { + continue; + } - imfins.smpnum = LittleEndianW(imfins.smpnum); - imfins.fadeout = LittleEndianW(imfins.fadeout); - // Orpheus does not check this! - //if(memcmp(imfins.ii10, "II10", 4) != 0) + //if(memcmp(instrumentHeader.ii10, "II10", 4) != 0) // return false; + instrumentHeader.ConvertToMPT(*instr, firstSample); - pIns = AllocateInstrument(nIns + 1); - if(pIns == nullptr) + // Read this instrument's samples + for(SAMPLEINDEX smp = 0; smp < instrumentHeader.smpNum; smp++) { - continue; - } + IMFSample sampleHeader; + file.ReadConvertEndianness(sampleHeader); + m_nSamples++; - StringFixer::ReadString<StringFixer::nullTerminated>(pIns->name, imfins.name); - - if(imfins.smpnum) - { - STATIC_ASSERT(CountOf(pIns->Keyboard) >= CountOf(imfins.map)); - for(size_t cNote = 0; cNote < CountOf(imfins.map); cNote++) + if(memcmp(sampleHeader.is10, "IS10", 4) || m_nSamples >= MAX_SAMPLES) { - pIns->Keyboard[cNote] = firstsample + imfins.map[cNote]; + continue; } - } - pIns->nFadeOut = imfins.fadeout; + ModSample &sample = Samples[firstSample + smp]; - LoadIMFEnvelope(&pIns->VolEnv, &imfins, IMF_ENV_VOL); - LoadIMFEnvelope(&pIns->PanEnv, &imfins, IMF_ENV_PAN); - LoadIMFEnvelope(&pIns->PitchEnv, &imfins, IMF_ENV_FILTER); - if((pIns->PitchEnv.dwFlags & ENV_ENABLED) != 0) - pIns->PitchEnv.dwFlags |= ENV_FILTER; - - // hack to get === to stop notes (from modplug's xm loader) - if(!pIns->VolEnv.dwFlags[ENV_ENABLED] && !pIns->nFadeOut) - pIns->nFadeOut = 8192; - - // read this instrument's samples - for(SAMPLEINDEX nSmp = 0; nSmp < imfins.smpnum; nSmp++) - { - ASSERT_CAN_READ(sizeof(IMFSAMPLE)); - IMFSAMPLE imfsmp; - memcpy(&imfsmp, lpStream + dwMemPos, sizeof(IMFSAMPLE)); - dwMemPos += sizeof(IMFSAMPLE); - m_nSamples++; - - if(memcmp(imfsmp.is10, "IS10", 4) != 0) - return false; - - ModSample &sample = Samples[firstsample + nSmp]; - - sample.Initialize(); - StringFixer::ReadString<StringFixer::nullTerminated>(sample.filename, imfsmp.filename); + sampleHeader.ConvertToMPT(sample); strcpy(m_szNames[m_nSamples], sample.filename); - uint32 byteLen = sample.nLength = LittleEndian(imfsmp.length); - sample.nLoopStart = LittleEndian(imfsmp.loop_start); - sample.nLoopEnd = LittleEndian(imfsmp.loop_end); - sample.nC5Speed = LittleEndian(imfsmp.C5Speed); - sample.nVolume = imfsmp.volume * 4; - sample.nPan = imfsmp.panning; - if(imfsmp.flags & 1) - sample.uFlags |= CHN_LOOP; - if(imfsmp.flags & 2) - sample.uFlags |= CHN_PINGPONGLOOP; - if(imfsmp.flags & 4) + if(sampleHeader.length) { - sample.uFlags |= CHN_16BIT; - sample.nLength /= 2; - sample.nLoopStart /= 2; - sample.nLoopEnd /= 2; - } - if(imfsmp.flags & 8) - sample.uFlags |= CHN_PANNING; - - if(byteLen) - { - ASSERT_CAN_READ(byteLen); - + FileReader sampleChunk = file.GetChunk(sampleHeader.length); SampleIO( - (imfsmp.flags & 4) ? SampleIO::_16bit : SampleIO::_8bit, + sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) - .ReadSample(sample, reinterpret_cast<LPCSTR>(lpStream + dwMemPos), byteLen); + .ReadSample(sample, sampleChunk); } - - dwMemPos += byteLen; } - firstsample += imfins.smpnum; + firstSample += instrumentHeader.smpNum; } return true; Modified: trunk/OpenMPT/soundlib/ModSequence.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/ModSequence.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -28,7 +28,7 @@ PATTERNINDEX* pArray, ORDERINDEX nSize, ORDERINDEX nCapacity, - const bool bDeletableArray) : + const bool bDeletableArray) : m_pSndFile(&rSf), m_pArray(pArray), m_nSize(nSize), @@ -40,7 +40,7 @@ {} -ModSequence::ModSequence(CSoundFile& rSf, ORDERINDEX nSize) : +ModSequence::ModSequence(CSoundFile& rSf, ORDERINDEX nSize) : m_pSndFile(&rSf), m_bDeletableArray(true), m_nInvalidIndex(GetInvalidPatIndex(MOD_TYPE_MPT)), @@ -121,7 +121,7 @@ if(GetLengthTailTrimmed() > specs.ordersMax) { #ifdef MODPLUG_TRACKER - if (m_pSndFile->GetpModDoc()) + if(m_pSndFile->GetpModDoc()) m_pSndFile->GetpModDoc()->AddToLog("WARNING: Order list has been trimmed!\n"); #endif // MODPLUG_TRACKER } @@ -159,7 +159,7 @@ { const ORDERINDEX nLength = GetLength(); if(nLength == 0) return 0; - ORDERINDEX next = min(nLength-1, start+1); + ORDERINDEX next = Util::Min(ORDERINDEX(nLength - 1), ORDERINDEX(start + 1)); while(next+1 < nLength && (*this)[next] == GetIgnoreIndex()) next++; return next; } @@ -170,7 +170,7 @@ { const ORDERINDEX nLength = GetLength(); if(start == 0 || nLength == 0) return 0; - ORDERINDEX prev = min(start-1, nLength-1); + ORDERINDEX prev = Util::Min(ORDERINDEX(start - 1), ORDERINDEX(nLength - 1)); while(prev > 0 && (*this)[prev] == GetIgnoreIndex()) prev--; return prev; } @@ -311,9 +311,9 @@ ModSequenceSet::ModSequenceSet(CSoundFile& sndFile) - : ModSequence(sndFile, m_Cache, s_nCacheSize, s_nCacheSize, NoArrayDelete), + : ModSequence(sndFile, m_Cache, s_nCacheSize, s_nCacheSize, false), m_nCurrentSeq(0) -//------------------------------------------------------------------- +//-------------------------------------------------------------- { m_Sequences.push_back(ModSequence(sndFile, s_nCacheSize)); } @@ -322,7 +322,7 @@ const ModSequence& ModSequenceSet::GetSequence(SEQUENCEINDEX nSeq) const //---------------------------------------------------------------------- { - if (nSeq == GetCurrentSequenceIndex()) + if(nSeq == GetCurrentSequenceIndex()) return *this; else return m_Sequences[nSeq]; @@ -332,7 +332,7 @@ ModSequence& ModSequenceSet::GetSequence(SEQUENCEINDEX nSeq) //---------------------------------------------------------- { - if (nSeq == GetCurrentSequenceIndex()) + if(nSeq == GetCurrentSequenceIndex()) return *this; else return m_Sequences[nSeq]; @@ -350,7 +350,7 @@ //--------------------------------------- { const ModSequence& rSeq = m_Sequences[m_nCurrentSeq]; - if (rSeq.GetLength() <= s_nCacheSize) + if(rSeq.GetLength() <= s_nCacheSize) { PATTERNINDEX* pOld = m_pArray; m_pArray = m_Cache; @@ -396,13 +396,13 @@ //-------------------------------------------------- { // Do nothing if index is invalid or if there's only one sequence left. - if (i >= m_Sequences.size() || m_Sequences.size() <= 1) + if(i >= m_Sequences.size() || m_Sequences.size() <= 1) return; const bool bSequenceChanges = (i == m_nCurrentSeq); m_Sequences.erase(m_Sequences.begin() + i); - if (i < m_nCurrentSeq || m_nCurrentSeq >= GetNumSequences()) + if(i < m_nCurrentSeq || m_nCurrentSeq >= GetNumSequences()) m_nCurrentSeq--; - if (bSequenceChanges) + if(bSequenceChanges) CopyStorageToCache(); } @@ -417,11 +417,11 @@ GetSequence(n).AdjustToNewModType(oldtype); } // Multisequences not suppported by other formats - if (oldtype != MOD_TYPE_NONE && newtype != MOD_TYPE_MPT) + if(oldtype != MOD_TYPE_NONE && newtype != MOD_TYPE_MPT) MergeSequences(); // Convert sequence with separator patterns into multiple sequences? - if (oldtype != MOD_TYPE_NONE && newtype == MOD_TYPE_MPT && GetNumSequences() == 1) + if(oldtype != MOD_TYPE_NONE && newtype == MOD_TYPE_MPT && GetNumSequences() == 1) ConvertSubsongsToMultipleSequences(); } @@ -430,7 +430,7 @@ //------------------------------------------------------- { // Allow conversion only if there's only one sequence. - if (GetNumSequences() != 1 || m_pSndFile->GetType() != MOD_TYPE_MPT) + if(GetNumSequences() != 1 || m_pSndFile->GetType() != MOD_TYPE_MPT) return false; bool hasSepPatterns = false; @@ -447,7 +447,7 @@ if(hasSepPatterns && Reporting::Confirm("The order list contains separator items.\nThe new format supports multiple sequences, do you want to convert those separate tracks into multiple song sequences?", - "Order list conversion") == cnfYes) + "Order list conversion", false, true) == cnfYes) { SetSequence(0); @@ -488,7 +488,7 @@ if(m_pSndFile->Patterns.IsValidPat(copyPat)) { ModCommand *m = m_pSndFile->Patterns[copyPat]; - for (UINT len = m_pSndFile->Patterns[copyPat].GetNumRows() * m_pSndFile->m_nChannels; len; m++, len--) + for(size_t len = m_pSndFile->Patterns[copyPat].GetNumRows() * m_pSndFile->m_nChannels; len; m++, len--) { if(m->command == CMD_POSITIONJUMP && m->param >= startOrd) { @@ -554,7 +554,7 @@ if(!m_pSndFile->Patterns.IsValidPat(nPat)) continue; ModCommand *m = m_pSndFile->Patterns[nPat]; - for (UINT len = 0; len < m_pSndFile->Patterns[nPat].GetNumRows() * m_pSndFile->m_nChannels; m++, len++) + for(size_t len = 0; len < m_pSndFile->Patterns[nPat].GetNumRows() * m_pSndFile->m_nChannels; m++, len++) { if(m->command == CMD_POSITIONJUMP) { Modified: trunk/OpenMPT/soundlib/ModSequence.h =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.h 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/ModSequence.h 2013-02-16 15:06:45 UTC (rev 1532) @@ -132,8 +132,6 @@ 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. - - static const bool NoArrayDelete = false; }; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -631,7 +631,7 @@ #endif // MODPLUG_TRACKER #endif // MODPLUG_BASIC_SUPPORT && !ReadGDM(file) - && !ReadIMF(lpStream, dwMemLength) + && !ReadIMF(file) && !ReadAM(file) && !ReadJ2B(file) && !ReadMO3(file) Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-16 15:06:45 UTC (rev 1532) @@ -415,7 +415,7 @@ bool ReadUMX(FileReader &file); bool ReadMO3(FileReader &file); bool ReadGDM(FileReader &file); - bool ReadIMF(const LPCBYTE lpStream, const DWORD dwMemLength); + bool ReadIMF(FileReader &file); bool ReadAM(FileReader &file); bool ReadJ2B(FileReader &file); bool ReadMID(const LPCBYTE lpStream, DWORD dwMemLength); Modified: trunk/OpenMPT/soundlib/patternContainer.cpp =================================================================== --- trunk/OpenMPT/soundlib/patternContainer.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/patternContainer.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -52,9 +52,8 @@ bool CPatternContainer::Insert(const PATTERNINDEX index, const ROWINDEX rows) //--------------------------------------------------------------------------- { - ASSERT(rows != 0); const CModSpecifications& specs = m_rSndFile.GetModSpecifications(); - if(index >= specs.patternsMax || index > m_Patterns.size() || rows > specs.patternRowsMax) + if(index >= specs.patternsMax || index > m_Patterns.size() || rows > specs.patternRowsMax || rows == 0) return true; if(index < m_Patterns.size() && m_Patterns[index]) return true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-16 20:12:09
|
Revision: 1533 http://sourceforge.net/p/modplug/code/1533 Author: saga-games Date: 2013-02-16 20:11:58 +0000 (Sat, 16 Feb 2013) Log Message: ----------- [Ref] Rewrote DMF loader to use FileReader (plus a few small improvements in pattern loading) Modified Paths: -------------- trunk/OpenMPT/mptrack/SelectPluginDialog.cpp trunk/OpenMPT/soundlib/LOAD_DMF.CPP trunk/OpenMPT/soundlib/Load_imf.cpp trunk/OpenMPT/soundlib/Loaders.h trunk/OpenMPT/soundlib/SampleIO.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/SelectPluginDialog.cpp =================================================================== --- trunk/OpenMPT/mptrack/SelectPluginDialog.cpp 2013-02-16 15:06:45 UTC (rev 1532) +++ trunk/OpenMPT/mptrack/SelectPluginDialog.cpp 2013-02-16 20:11:58 UTC (rev 1533) @@ -273,7 +273,7 @@ { VSTPluginLib::catSynth, "Instrument Plugins" }, }; - vector<bool> categoryUsed(VSTPluginLib::numCategories, false); + std::bitset<VSTPluginLib::numCategories> categoryUsed; HTREEITEM categoryFolders[VSTPluginLib::numCategories]; for(size_t i = CountOf(categories); i != 0; ) { Modified: trunk/OpenMPT/soundlib/LOAD_DMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2013-02-16 15:06:45 UTC (rev 1532) +++ trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2013-02-16 20:11:58 UTC (rev 1533) @@ -15,48 +15,17 @@ #include "stdafx.h" #include "Loaders.h" +#include "ChunkReader.h" #ifdef MODPLUG_TRACKER #include "../mptrack/Moddoc.h" #endif // MODPLUG_TRACKER -// 32-bit chunk identifiers -#define DMF_DDMF 0x464D4444 -#define DMF_CMSG 0x47534D43 -#define DMF_SEQU 0x55514553 -#define DMF_PATT 0x54544150 -#define DMF_SMPI 0x49504D53 -#define DMF_SMPD 0x44504D53 -#define DMF_SMPJ 0x4A504D53 -#define DMF_ENDE 0x45444E45 -#define DMF_SETT 0x9C219DE4 - -// Pattern flags - global track -#define DMFPAT_GLOBPACK 0x80 // Pack information for global track follows -#define DMFPAT_GLOBMASK 0x3F // Mask for global effects -// Pattern flags - note tracks -#define DMFPAT_COUNTER 0x80 // Pack information for current channel follows -#define DMFPAT_INSTR 0x40 // Instrument number present -#define DMFPAT_NOTE 0x20 // Note present -#define DMFPAT_VOLUME 0x10 // Volume present -#define DMFPAT_INSEFF 0x08 // Instrument effect present -#define DMFPAT_NOTEEFF 0x04 // Note effect present -#define DMFPAT_VOLEFF 0x02 // Volume effect stored - -// Sample flags -#define DMFSMP_LOOP 0x01 -#define DMFSMP_16BIT 0x02 -#define DMFSMP_COMPMASK 0x0C -#define DMFSMP_COMP1 0x04 // Compression type 1 -#define DMFSMP_COMP2 0x08 // Compression type 2 (unused) -#define DMFSMP_COMP3 0x0C // Compression type 3 (dito) -#define DMFSMP_LIBRARY 0x80 // Sample is stored in a library - #pragma pack(push, 1) // DMF header -struct DMFHEADER +struct DMFFileHeader { - uint32 signature; // "DDMF" + char signature[4]; // "DDMF" uint8 version; // 1 - 7 are beta versions, 8 is the official thing, 10 is xtracker32 char tracker[8]; // "XTRACKER" char songname[30]; @@ -66,50 +35,154 @@ uint8 creationYear; }; -struct DMF_IFFCHUNK +struct DMFChunk { - uint32 signature; // 4-letter identifier - uint32 chunksize; // chunk size without header + // 32-Bit chunk identifiers + enum ChunkIdentifiers + { + idCMSG = 0x47534D43, // Song message + idSEQU = 0x55514553, // Order list + idPATT = 0x54544150, // Patterns + idSMPI = 0x49504D53, // Sample headers + idSMPD = 0x44504D53, // Sample data + idSMPJ = 0x4A504D53, // Sample jump table (XTrakcker 32 only) + idENDE = 0x45444E45, // Last four bytes of DMF file + idSETT = 0x9C219DE4, // Probably contains GUI settings + }; + + typedef ChunkIdentifiers id_type; + + uint32 id; + uint32 length; + + size_t GetLength() const + { + uint32 l = length; + return SwapBytesLE(l); + } + + id_type GetID() const + { + uint32 i = id; + return static_cast<id_type>(SwapBytesLE(i)); + } }; // Order list -struct DMFCHUNK_SEQUENCE +struct DMFSequence { uint16 loopStart; uint16 loopEnd; // order list follows here ... + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + } }; // Pattern header (global) -struct DMFCHUNK_PATTERNS +struct DMFPatterns { uint16 numPatterns; // 1..1024 patterns uint8 numTracks; // 1..32 channels + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(numPatterns); + } }; // Pattern header (for each pattern) -struct DMFCHUNK_PATTERNHEADER +struct DMFPatternHeader { uint8 numTracks; // 1..32 channels uint8 beat; // [hi|lo] -> hi = rows per beat, lo = reserved uint16 numRows; uint32 patternLength; // patttern data follows here ... + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(numRows); + SwapBytesLE(patternLength); + } }; // Sample header -struct DMFCHUNK_SAMPLEHEADER +struct DMFSampleHeader { + enum SampleFlags + { + // Sample flags + smpLoop = 0x01, + smp16Bit = 0x02, + smpCompMask = 0x0C, + smpComp1 = 0x04, // Compression type 1 + smpComp2 = 0x08, // Compression type 2 (unused) + smpComp3 = 0x0C, // Compression type 3 (dito) + smpLibrary = 0x80, // Sample is stored in a library + }; + uint32 length; uint32 loopStart; uint32 loopEnd; uint16 c3freq; // 1000..45000hz uint8 volume; // 0 = ignore uint8 flags; + + // Convert an DMFSampleHeader to OpenMPT's internal sample representation. + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + mptSmp.nLength = length; + mptSmp.nSustainEnd = loopEnd; + mptSmp.nSustainStart = loopStart; + if(mptSmp.nSustainEnd > 0) + { + mptSmp.nSustainEnd--; + } + mptSmp.SanitizeLoops(); + + mptSmp.nC5Speed = c3freq; + mptSmp.nGlobalVol = 64; + if(volume) + { + mptSmp.nVolume = volume + 1; + } else + { + mptSmp.nVolume = 256; + } + + if((flags & smpLoop) != 0 && mptSmp.nSustainEnd > mptSmp.nSustainStart) + { + mptSmp.uFlags.set(CHN_SUSTAINLOOP); + } + if((flags & smp16Bit) != 0) + { + mptSmp.uFlags.set(CHN_16BIT); + mptSmp.nLength /= 2; + mptSmp.nSustainStart /= 2; + mptSmp.nSustainEnd /= 2; + } + } + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(length); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(c3freq); + } }; // Sample header tail (between head and tail, there might be the library name of the sample, depending on the DMF version) -struct DMFCHUNK_SAMPLEHEADERTAIL +struct DMFSampleHeaderTail { uint16 filler; uint32 crc32; @@ -118,22 +191,48 @@ #pragma pack(pop) // Pattern translation memory -struct DMF_PATTERNSETTINGS +struct DMFPatternSettings { - vector<ModCommand::NOTE> noteBuffer; // Note buffer - vector<ModCommand::NOTE> lastNote; // Last played note on channel - vector<bool> playDir; // Sample play direction of each channel... false = forward (default) + struct ChannelState + { + ModCommand::NOTE noteBuffer; // Note buffer + ModCommand::NOTE lastNote; // Last played note on channel + uint8 vibratoType; // Last used vibrato type on channel + uint8 tremoloType; // Last used tremolo type on channel + uint8 highOffset; // Last used high offset on channel + bool playDir; // Sample play direction... false = forward (default) + + ChannelState() + { + noteBuffer = lastNote = NOTE_NONE; + vibratoType = 8; + tremoloType = 4; + highOffset = 0; + playDir = false; + } + }; + + vector<ChannelState> channels; // Memory for each channel's state bool realBPMmode; // true = BPM mode uint8 beat; // Rows per beat uint8 tempoTicks; // Tick mode param uint8 tempoBPM; // BPM mode param uint8 internalTicks; // Ticks per row in final pattern + + DMFPatternSettings(CHANNELINDEX numChannels) : channels(numChannels) + { + realBPMmode = false; + beat = 0; + tempoTicks = 32; + tempoBPM = 120; + internalTicks = 6; + } }; // Convert portamento value (not very accurate due to X-Tracker's higher granularity, to say the least) -uint8 DMFporta2MPT(uint8 val, const uint8 internalTicks, const bool hasFine) -//-------------------------------------------------------------------------- +static uint8 DMFporta2MPT(uint8 val, const uint8 internalTicks, const bool hasFine) +//--------------------------------------------------------------------------------- { if(val == 0) return 0; @@ -145,8 +244,8 @@ // Convert portamento / volume slide value (not very accurate due to X-Tracker's higher granularity, to say the least) -uint8 DMFslide2MPT(uint8 val, const uint8 internalTicks, const bool up) -//--------------------------------------------------------------------- +static uint8 DMFslide2MPT(uint8 val, const uint8 internalTicks, const bool up) +//---------------------------------------------------------------------------- { val = max(1, val / 4); const bool isFine = (val < 0x0F) || (internalTicks < 2); @@ -162,8 +261,8 @@ // Calculate tremor on/off param -uint8 DMFtremor2MPT(uint8 val, const uint8 internalTicks) -//------------------------------------------------------- +static uint8 DMFtremor2MPT(uint8 val, const uint8 internalTicks) +//-------------------------------------------------------------- { uint8 ontime = (val >> 4); uint8 offtime = (val & 0x0F); @@ -174,8 +273,8 @@ // Calculate delay parameter for note cuts / delays -uint8 DMFdelay2MPT(uint8 val, const uint8 internalTicks) -//------------------------------------------------------ +static uint8 DMFdelay2MPT(uint8 val, const uint8 internalTicks) +//------------------------------------------------------------- { int newval = (int)val * (int)internalTicks / 255; Limit(newval, 0, 15); @@ -184,8 +283,8 @@ // Convert vibrato-style command parameters -uint8 DMFvibrato2MPT(uint8 val, const uint8 internalTicks) -//-------------------------------------------------------- +static uint8 DMFvibrato2MPT(uint8 val, const uint8 internalTicks) +//--------------------------------------------------------------- { // MPT: 1 vibrato period == 64 ticks... we have internalTicks ticks per row. // X-Tracker: Period length specified in rows! @@ -196,8 +295,8 @@ // Try using effect memory (zero paramer) to give the effect swapper some optimization hints. -void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX numChannels, uint8 effect, uint8 ¶m) -//------------------------------------------------------------------------------------------------------------- +static void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX numChannels, uint8 effect, uint8 ¶m) +//-------------------------------------------------------------------------------------------------------------------- { if(effect == CMD_NONE || param == 0) { @@ -259,71 +358,81 @@ } -PATTERNINDEX ConvertDMFPattern(const LPCBYTE lpStream, const DWORD dwMemLength, DMF_PATTERNSETTINGS &settings, CSoundFile *pSndFile) -//---------------------------------------------------------------------------------------------------------------------------------- +static PATTERNINDEX ConvertDMFPattern(FileReader &file, DMFPatternSettings &settings, CSoundFile &sndFile) +//-------------------------------------------------------------------------------------------------------- { - #define ASSERT_CAN_READ_PATTERN(x) ASSERT_CAN_READ_PROTOTYPE(dwMemPos, dwMemLength, x, return nPat); + // Pattern flags + enum PatternFlags + { + // Global Track + patGlobPack = 0x80, // Pack information for global track follows + patGlobMask = 0x3F, // Mask for global effects + // Note tracks + patCounter = 0x80, // Pack information for current channel follows + patInstr = 0x40, // Instrument number present + patNote = 0x20, // Note present + patVolume = 0x10, // Volume present + patInsEff = 0x08, // Instrument effect present + patNoteEff = 0x04, // Note effect present + patVolEff = 0x02, // Volume effect stored + }; - DWORD dwMemPos = 0; + file.Rewind(); + + DMFPatternHeader patHead; + file.ReadConvertEndianness(patHead); - // ASSERT_CAN_READ_PATTERN(sizeof(DMFCHUNK_PATTERNHEADER)); -- already done in main loop - DMFCHUNK_PATTERNHEADER *patHead = (DMFCHUNK_PATTERNHEADER *)(lpStream + dwMemPos); - dwMemPos += sizeof(DMFCHUNK_PATTERNHEADER); - - const ROWINDEX numRows = CLAMP(LittleEndianW(patHead->numRows), 1, MAX_PATTERN_ROWS); - const PATTERNINDEX nPat = pSndFile->Patterns.Insert(numRows); - if(nPat == PATTERNINDEX_INVALID) + const ROWINDEX numRows = Clamp(ROWINDEX(patHead.numRows), ROWINDEX(1), MAX_PATTERN_ROWS); + const PATTERNINDEX pat = sndFile.Patterns.Insert(numRows); + if(pat == PATTERNINDEX_INVALID) { - return nPat; + return pat; } - ModCommand *m = pSndFile->Patterns[nPat]; - const CHANNELINDEX numChannels = min(pSndFile->GetNumChannels(), patHead->numTracks); + PatternRow m = sndFile.Patterns[pat].GetRow(0); + const CHANNELINDEX numChannels = Util::Min(sndFile.GetNumChannels(), CHANNELINDEX(patHead.numTracks)); // When breaking to a pattern with less channels that the previous pattern, // all voices in the now unused channels are killed: - for(CHANNELINDEX nChn = numChannels + 1; nChn < pSndFile->GetNumChannels(); nChn++) + for(CHANNELINDEX chn = numChannels + 1; chn < sndFile.GetNumChannels(); chn++) { - m[nChn].note = NOTE_NOTECUT; + m[chn].note = NOTE_NOTECUT; } // Initialize tempo stuff - settings.beat = (patHead->beat >> 4); + settings.beat = (patHead.beat >> 4); bool tempoChange = settings.realBPMmode; uint8 writeDelay = 0; // Counters for channel packing (including global track) vector<uint8> channelCounter(numChannels + 1, 0); - for(ROWINDEX nRow = 0; nRow < numRows; nRow++) + for(ROWINDEX row = 0; row < numRows; row++) { // Global track info counter reached 0 => read global track data if(channelCounter[0] == 0) { - ASSERT_CAN_READ_PATTERN(1); - uint8 globalInfo = lpStream[dwMemPos++]; + uint8 globalInfo = file.ReadUint8(); // 0x80: Packing counter (if not present, counter stays at 0) - if((globalInfo & DMFPAT_GLOBPACK) != 0) + if((globalInfo & patGlobPack) != 0) { - ASSERT_CAN_READ_PATTERN(1); - channelCounter[0] = lpStream[dwMemPos++]; + channelCounter[0] = file.ReadUint8(); } - globalInfo &= DMFPAT_GLOBMASK; + globalInfo &= patGlobMask; uint8 globalData = 0; if(globalInfo != 0) { - ASSERT_CAN_READ_PATTERN(1); - globalData = lpStream[dwMemPos++]; + globalData = file.ReadUint8(); } switch(globalInfo) { case 1: // Set Tick Frame Speed settings.realBPMmode = false; - settings.tempoTicks = max(1, globalData); // Tempo in 1/4 rows per second - settings.tempoBPM = 0; // Automatically updated by X-Tracker + settings.tempoTicks = Util::Max(uint8(1), globalData); // Tempo in 1/4 rows per second + settings.tempoBPM = 0; // Automatically updated by X-Tracker tempoChange = true; break; case 2: // Set BPM Speed (real BPM mode) @@ -405,7 +514,7 @@ // For some reason, using settings.tempoTicks + 1 gives more accurate results than just settings.tempoTicks... (same problem in the old libmodplug DMF loader) // Original unoptimized formula: //const int tickspeed = (tempoRealBPMmode) ? max(1, (tempoData * beat * 4) / 60) : tempoData; - const int tickspeed = (settings.realBPMmode) ? max(1, settings.tempoBPM * settings.beat * 2) : ((settings.tempoTicks + 1) * 30); + const int tickspeed = (settings.realBPMmode) ? Util::Max(1, settings.tempoBPM * settings.beat * 2) : ((settings.tempoTicks + 1) * 30); // Try to find matching speed - try higher speeds first, so that effects like arpeggio and tremor work better. for(speed = 255; speed > 1; speed--) { @@ -425,30 +534,27 @@ } } - m = pSndFile->Patterns[nPat].GetpModCommand(nRow, 1); // Reserve first channel for global effects + m = sndFile.Patterns[pat].GetpModCommand(row, 1); // Reserve first channel for global effects - for(CHANNELINDEX nChn = 1; nChn <= numChannels; nChn++, m++) + for(CHANNELINDEX chn = 1; chn <= numChannels; chn++, m++) { // Track info counter reached 0 => read track data - if(channelCounter[nChn] == 0) + if(channelCounter[chn] == 0) { - ASSERT_CAN_READ_PATTERN(1); - const uint8 channelInfo = lpStream[dwMemPos++]; + const uint8 channelInfo = file.ReadUint8(); //////////////////////////////////////////////////////////////// // 0x80: Packing counter (if not present, counter stays at 0) - if((channelInfo & DMFPAT_COUNTER) != 0) + if((channelInfo & patCounter) != 0) { - ASSERT_CAN_READ_PATTERN(1); - channelCounter[nChn] = lpStream[dwMemPos++]; + channelCounter[chn] = file.ReadUint8(); } //////////////////////////////////////////////////////////////// // 0x40: Instrument bool slideNote = true; // If there is no instrument number next to a note, the note is not retriggered! - if((channelInfo & DMFPAT_INSTR) != 0) + if((channelInfo & patInstr) != 0) { - ASSERT_CAN_READ_PATTERN(1); - m->instr = lpStream[dwMemPos++]; + m->instr = file.ReadUint8(); if(m->instr != 0) { slideNote = false; @@ -457,19 +563,18 @@ //////////////////////////////////////////////////////////////// // 0x20: Note - if((channelInfo & DMFPAT_NOTE) != 0) + if((channelInfo & patNote) != 0) { - ASSERT_CAN_READ_PATTERN(1); - m->note = lpStream[dwMemPos++]; + m->note = file.ReadUint8(); if(m->note >= 1 && m->note <= 108) { - m->note = CLAMP(m->note + 24, NOTE_MIN, NOTE_MAX); - settings.lastNote[nChn] = m->note; + m->note = static_cast<uint8>(Clamp(m->note + 24, NOTE_MIN, NOTE_MAX)); + settings.channels[chn].lastNote = m->note; } else if(m->note >= 129 && m->note <= 236) { // "Buffer notes" for portamento (and other effects?) that are actually not played, but just "queued"... - m->note = CLAMP((m->note & 0x7F) + 24, NOTE_MIN, NOTE_MAX); - settings.noteBuffer[nChn] = m->note; + m->note = static_cast<uint8>(Clamp((m->note & 0x7F) + 24, NOTE_MIN, NOTE_MAX)); + settings.channels[chn].noteBuffer = m->note; m->note = NOTE_NONE; } else if(m->note == 255) { @@ -480,13 +585,13 @@ // If there's just an instrument number, but no note, retrigger sample. if(m->note == NOTE_NONE && m->instr > 0) { - m->note = settings.lastNote[nChn]; + m->note = settings.channels[chn].lastNote; m->instr = 0; } if(m->IsNote()) { - settings.playDir[nChn] = false; + settings.channels[chn].playDir = false; } uint8 effect1 = CMD_NONE, effect2 = CMD_NONE, effect3 = CMD_NONE; @@ -495,20 +600,18 @@ //////////////////////////////////////////////////////////////// // 0x10: Volume - if((channelInfo & DMFPAT_VOLUME) != 0) + if((channelInfo & patVolume) != 0) { - ASSERT_CAN_READ_PATTERN(1); m->volcmd = VOLCMD_VOLUME; - m->vol = (lpStream[dwMemPos++] + 3) / 4; + m->vol = (file.ReadUint8() + 3) / 4; } //////////////////////////////////////////////////////////////// // 0x08: Instrument effect - if((channelInfo & DMFPAT_INSEFF) != 0) + if((channelInfo & patInsEff) != 0) { - ASSERT_CAN_READ_PATTERN(2); - effect1 = lpStream[dwMemPos++]; - effectParam1 = lpStream[dwMemPos++]; + effect1 = file.ReadUint8(); + effectParam1 = file.ReadUint8(); switch(effect1) { @@ -521,8 +624,8 @@ effect1 = CMD_NONE; break; case 3: // Instrument Volume Override (aka "Restart") - m->note = settings.lastNote[nChn]; - settings.playDir[nChn] = false; + m->note = settings.channels[chn].lastNote; + settings.channels[chn].playDir = false; effect1 = CMD_NONE; break; case 4: // Sample Delay @@ -537,34 +640,37 @@ } if(m->note == NOTE_NONE) { - m->note = settings.lastNote[nChn]; - settings.playDir[nChn] = false; + m->note = settings.channels[chn].lastNote; + settings.channels[chn].playDir = false; } break; case 5: // Tremolo Retrig Sample (who invented those stupid effect names?) effectParam1 = max(1, DMFdelay2MPT(effectParam1, settings.internalTicks)); effect1 = CMD_RETRIG; - settings.playDir[nChn] = false; + settings.channels[chn].playDir = false; break; case 6: // Offset case 7: // Offset + 64k case 8: // Offset + 128k case 9: // Offset + 192k // Put high offset on previous row - if(nRow > 0) + if(row > 0 && effect1 != settings.channels[chn].highOffset) { - pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (effect1 - 6))).Row(nRow - 1).Channel(nChn).Retry(EffectWriter::rmTryPreviousRow)); + if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (effect1 - 6))).Row(row - 1).Channel(chn).Retry(EffectWriter::rmTryPreviousRow))) + { + settings.channels[chn].highOffset = effect1; + } } effect1 = CMD_OFFSET; - settings.playDir[nChn] = false; + settings.channels[chn].playDir = false; break; case 10: // Invert Sample play direction ("Tekkno Invert") effect1 = CMD_S3MCMDEX; - if(settings.playDir[nChn] == false) + if(settings.channels[chn].playDir == false) effectParam1 = 0x9F; else effectParam1 = 0x9E; - settings.playDir[nChn] = !settings.playDir[nChn]; + settings.channels[chn].playDir = !settings.channels[chn].playDir; break; default: effect1 = CMD_NONE; @@ -574,11 +680,10 @@ //////////////////////////////////////////////////////////////// // 0x04: Note effect - if((channelInfo & DMFPAT_NOTEEFF) != 0) + if((channelInfo & patNoteEff) != 0) { - ASSERT_CAN_READ_PATTERN(2); - effect2 = lpStream[dwMemPos++]; - effectParam2 = lpStream[dwMemPos++]; + effect2 = file.ReadUint8(); + effectParam2 = file.ReadUint8(); switch(effect2) { @@ -612,7 +717,7 @@ case 6: // Portamento to Note if(m->note == NOTE_NONE) { - m->note = settings.noteBuffer[nChn]; + m->note = settings.channels[chn].noteBuffer; } effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, false); effect2 = CMD_TONEPORTAMENTO; @@ -628,9 +733,12 @@ case 9: // Vibrato Triangle (ramp down should be close enough) case 10: // Vibrato Square // Put vibrato type on previous row - if(nRow > 0) + if(row > 0 && effect2 != settings.channels[chn].vibratoType) { - pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (effect2 - 8))).Row(nRow - 1).Channel(nChn).Retry(EffectWriter::rmTryPreviousRow)); + if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (effect2 - 8))).Row(row - 1).Channel(chn).Retry(EffectWriter::rmTryPreviousRow))) + { + settings.channels[chn].vibratoType = effect2; + } } effect2 = CMD_VIBRATO; effectParam2 = DMFvibrato2MPT(effectParam2, settings.internalTicks); @@ -662,11 +770,10 @@ //////////////////////////////////////////////////////////////// // 0x02: Volume effect - if((channelInfo & DMFPAT_VOLEFF) != 0) + if((channelInfo & patVolEff) != 0) { - ASSERT_CAN_READ_PATTERN(2); - effect3 = lpStream[dwMemPos++]; - effectParam3 = lpStream[dwMemPos++]; + effect3 = file.ReadUint8(); + effectParam3 = file.ReadUint8(); switch(effect3) { @@ -685,9 +792,12 @@ case 5: // Tremolo Triangle (ramp down should be close enough) case 6: // Tremolo Square // Put tremolo type on previous row - if(nRow > 0) + if(row > 0 && effect3 != settings.channels[chn].tremoloType) { - pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (effect3 - 4))).Row(nRow - 1).Channel(nChn).Retry(EffectWriter::rmTryPreviousRow)); + if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (effect3 - 4))).Row(row - 1).Channel(chn).Retry(EffectWriter::rmTryPreviousRow))) + { + settings.channels[chn].tremoloType = effect3; + } } effect3 = CMD_TREMOLO; effectParam3 = DMFvibrato2MPT(effectParam3, settings.internalTicks); @@ -716,11 +826,11 @@ // Let's see if we can help the effect swapper by reducing some effect parameters to "continue" parameters. if(useMem2) { - ApplyEffectMemory(m, nRow, pSndFile->GetNumChannels(), effect2, effectParam2); + ApplyEffectMemory(m, row, sndFile.GetNumChannels(), effect2, effectParam2); } if(useMem3) { - ApplyEffectMemory(m, nRow, pSndFile->GetNumChannels(), effect3, effectParam3); + ApplyEffectMemory(m, row, sndFile.GetNumChannels(), effect3, effectParam3); } // I guess this is close enough to "not retriggering the note" @@ -797,7 +907,7 @@ } else { - channelCounter[nChn]--; + channelCounter[chn]--; } } // End for all channels @@ -806,295 +916,156 @@ { tempoChange = false; - pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_TEMPO, static_cast<ModCommand::PARAM>(tempo)).Row(nRow).Channel(0).Retry(EffectWriter::rmTryNextRow)); - pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_SPEED, static_cast<ModCommand::PARAM>(speed)).Row(nRow).Retry(EffectWriter::rmTryNextRow)); + sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_TEMPO, static_cast<ModCommand::PARAM>(tempo)).Row(row).Channel(0).Retry(EffectWriter::rmTryNextRow)); + sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, static_cast<ModCommand::PARAM>(speed)).Row(row).Retry(EffectWriter::rmTryNextRow)); } // Try to put delay effects somewhere as well if(writeDelay & 0xF0) { - pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4)).Row(nRow).AllowMultiple().Retry(EffectWriter::rmIgnore)); + sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4)).Row(row).AllowMultiple().Retry(EffectWriter::rmIgnore)); } if(writeDelay & 0x0F) { const uint8 param = (writeDelay & 0x0F) * settings.internalTicks / 15; - pSndFile->Patterns[nPat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x60u | Clamp(param, uint8(1), uint8(15))).Row(nRow).AllowMultiple().Retry(EffectWriter::rmIgnore)); + sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x60u | Clamp(param, uint8(1), uint8(15))).Row(row).AllowMultiple().Retry(EffectWriter::rmIgnore)); } writeDelay = 0; } // End for all rows - return nPat; - - #undef ASSERT_CAN_READ_PATTERN - + return pat; } -DWORD ConvertDMFSample(const SAMPLEINDEX nSmp, const LPCBYTE lpStream, const DWORD dwMemLength, const bool isV8, uint8 &sampleFlags, CSoundFile *pSndFile) -//-------------------------------------------------------------------------------------------------------------------------------------------------------- +bool CSoundFile::ReadDMF(FileReader &file) +//---------------------------------------- { - #define ASSERT_CAN_READ_SAMPLE(x) ASSERT_CAN_READ_PROTOTYPE(dwMemPos, dwMemLength, x, return 0); - - DWORD dwMemPos = 0; - - ASSERT_CAN_READ_SAMPLE(1); - const size_t lenName = lpStream[dwMemPos++]; - ASSERT_CAN_READ_SAMPLE(lenName); - StringFixer::ReadString<StringFixer::spacePadded>(pSndFile->m_szNames[nSmp], reinterpret_cast<const char *>(lpStream + dwMemPos), lenName); - dwMemPos += lenName; - - ASSERT_CAN_READ_SAMPLE(sizeof(DMFCHUNK_SAMPLEHEADER)); - DMFCHUNK_SAMPLEHEADER *smpHead = (DMFCHUNK_SAMPLEHEADER *)(lpStream + dwMemPos); - dwMemPos += sizeof(DMFCHUNK_SAMPLEHEADER); - - ModSample &sample = pSndFile->GetSample(nSmp); - sample.Initialize(); - sample.nLength = LittleEndian(smpHead->length); - sample.nSustainEnd = min(sample.nLength, LittleEndian(smpHead->loopEnd)); - sample.nSustainStart = min(sample.nSustainEnd, LittleEndian(smpHead->loopStart)); - if(sample.nSustainEnd > 0) + DMFFileHeader fileHeader; + file.Rewind(); + if(!file.Read(fileHeader) + || memcmp(fileHeader.signature, "DDMF", 4) + || !fileHeader.version || fileHeader.version > 10) { - sample.nSustainEnd--; - } - - sample.nC5Speed = LittleEndianW(smpHead->c3freq); - sample.nGlobalVol = 64; - if(smpHead->volume) - { - sample.nVolume = smpHead->volume + 1; - } else - { - sample.nVolume = 256; - } - sampleFlags = smpHead->flags; - if((sampleFlags & DMFSMP_LOOP) != 0 && sample.nSustainEnd > sample.nSustainStart) - { - sample.uFlags |= CHN_SUSTAINLOOP; - } - if((sampleFlags & DMFSMP_16BIT) != 0) - { - sample.uFlags |= CHN_16BIT; - sample.nLength /= 2; - sample.nSustainStart /= 2; - sample.nSustainEnd /= 2; - } - - if(isV8) - { - // Read library name in version 8 files - ASSERT_CAN_READ_SAMPLE(8); - StringFixer::ReadString<StringFixer::spacePadded>(sample.filename, reinterpret_cast<const char *>(lpStream + dwMemPos), 8); - dwMemPos += 8; - } - - ASSERT_CAN_READ_SAMPLE(sizeof(DMFCHUNK_SAMPLEHEADERTAIL)); - // We don't care for the checksum of the sample data... - dwMemPos += sizeof(DMFCHUNK_SAMPLEHEADERTAIL); - - return dwMemPos; - - #undef ASSERT_CAN_READ_SAMPLE - -} - - -bool CSoundFile::ReadDMF(const BYTE *lpStream, const DWORD dwMemLength) -//--------------------------------------------------------------------- -{ - #define ASSERT_CAN_READ_CHUNK(x) ASSERT_CAN_READ_PROTOTYPE(dwMemPos, dwChunkEnd, x, break); - - DWORD dwMemPos = 0; - - ASSERT_CAN_READ(sizeof(DMFHEADER)); - DMFHEADER *pHeader = (DMFHEADER *)lpStream; - if(pHeader->signature != LittleEndian(DMF_DDMF) || !pHeader->version || pHeader->version > 10) - { return false; } - dwMemPos += sizeof(DMFHEADER); - StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], pHeader->songname); - m_nChannels = 0; + StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], fileHeader.songname); #ifdef MODPLUG_TRACKER if(GetpModDoc() != nullptr) { FileHistory mptHistory; MemsetZero(mptHistory); - mptHistory.loadDate.tm_mday = CLAMP(pHeader->creationDay, 0, 31); - mptHistory.loadDate.tm_mon = CLAMP(pHeader->creationMonth, 1, 12) - 1; - mptHistory.loadDate.tm_year = pHeader->creationYear; + mptHistory.loadDate.tm_mday = Clamp(fileHeader.creationDay, uint8(0), uint8(31)); + mptHistory.loadDate.tm_mon = Clamp(fileHeader.creationMonth, uint8(1), uint8(12)) - 1; + mptHistory.loadDate.tm_year = fileHeader.creationYear; GetpModDoc()->GetFileHistory().clear(); GetpModDoc()->GetFileHistory().push_back(mptHistory); } #endif // MODPLUG_TRACKER - vector<uint8> sampleFlags; - vector<DWORD> patternOffset; - vector<DWORD> patternLength; + // Go through all chunks now + ChunkReader chunkFile(file); + ChunkReader::ChunkList<DMFChunk> chunks = chunkFile.ReadChunks<DMFChunk>(1); + FileReader chunk; - ORDERINDEX loopStart = 0, loopEnd = ORDERINDEX_INVALID; + // Read order list + DMFSequence seqHeader; + chunk = chunks.GetChunk(DMFChunk::idSEQU); + if(!chunk.ReadConvertEndianness(seqHeader)) + { + return false; + } + const ORDERINDEX numOrders = Util::Min(MAX_ORDERS, static_cast<ORDERINDEX>((chunk.GetLength() - sizeof(DMFSequence)) / 2)); + Order.resize(numOrders, Order.GetInvalidPatIndex()); - // go through all chunks now - while(dwMemPos < dwMemLength) + for(ORDERINDEX i = 0; i < numOrders; i++) { - // Special case: Last 4 bytes should be "ENDE", without a size field (WTF) - ASSERT_CAN_READ(4); - if(*(uint32 *)(lpStream + dwMemPos) == LittleEndian(DMF_ENDE)) - { - break; - } + Order[i] = chunk.ReadUint16LE(); + } - ASSERT_CAN_READ(sizeof(DMF_IFFCHUNK)); - DMF_IFFCHUNK chunkheader = *(DMF_IFFCHUNK *)(lpStream + dwMemPos); - dwMemPos += sizeof(DMF_IFFCHUNK); + // Read patterns + chunk = chunks.GetChunk(DMFChunk::idPATT); + if(chunk.IsValid()) + { + DMFPatterns patHeader; + chunk.ReadConvertEndianness(patHeader); + m_nChannels = Clamp(patHeader.numTracks, uint8(1), uint8(32)) + 1; // + 1 for global track (used for tempo stuff) - chunkheader.signature = LittleEndian(chunkheader.signature); - chunkheader.chunksize = LittleEndian(chunkheader.chunksize); - ASSERT_CAN_READ(chunkheader.chunksize); + vector<FileReader> patternChunks; + patternChunks.reserve(patHeader.numPatterns); - const DWORD dwChunkEnd = dwMemPos + chunkheader.chunksize; - - switch(chunkheader.signature) + // First, find out where all of our patterns are... + for(PATTERNINDEX pat = 0; pat < patHeader.numPatterns; pat++) { - case DMF_CMSG: // "CMSG" - Song message - ASSERT_CAN_READ_CHUNK(1); - dwMemPos++; // filler byte - ReadFixedLineLengthMessage(lpStream + dwMemPos, chunkheader.chunksize - 1, 40, 0); - break; + DMFPatternHeader header; + chunk.ReadConvertEndianness(header); + chunk.SkipBack(sizeof(header)); + patternChunks.push_back(chunk.GetChunk(sizeof(header) + header.patternLength)); + } - case DMF_SEQU: // "SEQU" - Order list - { - ASSERT_CAN_READ_CHUNK(sizeof(DMFCHUNK_SEQUENCE)); - DMFCHUNK_SEQUENCE *seqHead = (DMFCHUNK_SEQUENCE *)(lpStream + dwMemPos); - dwMemPos += sizeof(DMFCHUNK_SEQUENCE); + // Now go through the order list and load them. + DMFPatternSettings settings(GetNumChannels()); - loopStart = LittleEndianW(seqHead->loopStart); - loopEnd = LittleEndianW(seqHead->loopEnd); - const ORDERINDEX numOrders = (ORDERINDEX)min(MAX_ORDERS, (chunkheader.chunksize - sizeof(DMFCHUNK_SEQUENCE)) / 2); - Order.resize(numOrders, Order.GetInvalidPatIndex()); - - for(ORDERINDEX i = 0; i < numOrders; i++, dwMemPos += 2) - { - uint16 orderItem = *(uint16 *)(lpStream + dwMemPos); - Order[i] = (PATTERNINDEX)LittleEndianW(orderItem); - } - } - break; - - case DMF_PATT: // "PATT" - Pattern data - if(m_nChannels == 0) + for(ORDERINDEX ord = 0; ord < Order.GetLength(); ord++) + { + // Create one pattern for each order item, as the same pattern can be played with different settings + PATTERNINDEX pat = Order[ord]; + if(pat < patternChunks.size()) { - ASSERT_CAN_READ_CHUNK(sizeof(DMFCHUNK_PATTERNS)); - DMFCHUNK_PATTERNS *patInfo = (DMFCHUNK_PATTERNS *)(lpStream + dwMemPos); - dwMemPos += sizeof(DMFCHUNK_PATTERNS); - m_nChannels = CLAMP(patInfo->numTracks, 1, 32) + 1; // + 1 for global track (used for tempo stuff) - - const PATTERNINDEX numPats = min(MAX_PATTERNS, LittleEndianW(patInfo->numPatterns)); - patternOffset.assign(numPats, 0); - patternLength.assign(numPats, 0); - - for(PATTERNINDEX nPat = 0; nPat < numPats; nPat++) + pat = ConvertDMFPattern(patternChunks[pat], settings, *this); + Order[ord] = pat; + // Loop end? + if(pat != PATTERNINDEX_INVALID && ord == seqHeader.loopEnd && (seqHeader.loopStart > 0 || ord < Order.GetLength() - 1)) { - ASSERT_CAN_READ_CHUNK(sizeof(DMFCHUNK_PATTERNHEADER)); - DMFCHUNK_PATTERNHEADER *patHead = (DMFCHUNK_PATTERNHEADER *)(lpStream + dwMemPos); - - patternOffset[nPat] = dwMemPos; - patternLength[nPat] = sizeof(DMFCHUNK_PATTERNHEADER) + LittleEndian(patHead->patternLength); - - ASSERT_CAN_READ_CHUNK(patternLength[nPat]); - dwMemPos += patternLength[nPat]; + Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(seqHeader.loopStart)).Row(Patterns[pat].GetNumRows() - 1).Retry(EffectWriter::rmTryPreviousRow)); } } - break; - - case DMF_SMPI: // "SMPI" - Sample headers - if(m_nSamples == 0) - { - ASSERT_CAN_READ_CHUNK(1); - m_nSamples = (SAMPLEINDEX)min(MAX_SAMPLES - 1, lpStream[dwMemPos]); - dwMemPos++; - - sampleFlags.assign(m_nSamples, 0); - for(SAMPLEINDEX nSmp = 0; nSmp < m_nSamples; nSmp++) - { - const DWORD bytesRead = ConvertDMFSample(nSmp + 1, lpStream + dwMemPos, dwChunkEnd - dwMemPos, (pHeader->version >= 8), sampleFlags[nSmp], this); - if(bytesRead == 0) - { - break; - } - dwMemPos += bytesRead; - } - - } - break; - - case DMF_SMPD: // "SMPD" - Sample data - for(SAMPLEINDEX nSmp = 1; nSmp <= m_nSamples; nSmp++) - { - ASSERT_CAN_READ_CHUNK(4); - const uint32 length = LittleEndian(*(uint32 *)(lpStream + dwMemPos)); - dwMemPos += 4; - ASSERT_CAN_READ_CHUNK(length); - - if(length > 0) - { - SampleIO( - (Samples[nSmp].uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, - SampleIO::mono, - SampleIO::littleEndian, - ((sampleFlags[nSmp - 1] & DMFSMP_COMPMASK) == DMFSMP_COMP1) ? SampleIO::DMF : SampleIO::signedPCM) - .ReadSample(Samples[nSmp], (LPCSTR)(lpStream + dwMemPos), length); - - dwMemPos += length; - } - } - break; - - case DMF_SMPJ: // "SMPJ" - Sample jump points (xtracker32 only) - case DMF_SETT: // "Unprintable ID" - those might be GUI settings and other related stuff - break; - -#ifdef DEBUG - default: - { - char s[40]; - const char *sig = (char *)&chunkheader.signature; - wsprintf(s, "Unknown chunk ID %c%c%c%c at %d\n", sig[0], sig[1], sig[2], sig[3], dwMemPos - sizeof(DMF_IFFCHUNK)); - if(GetpModDoc()) GetpModDoc()->AddToLog(s); - } -#endif } + } else + { + return false; + } - dwMemPos = dwChunkEnd; + // Read song message + chunk = chunks.GetChunk(DMFChunk::idCMSG); + if(chunk.IsValid()) + { + ReadFixedLineLengthMessage(chunk, chunk.GetLength() - 1, 40, 0); } + + // Read sample headers + data + FileReader sampleDataChunk = chunks.GetChunk(DMFChunk::idSMPD); + chunk = chunks.GetChunk(DMFChunk::idSMPI); + m_nSamples = chunk.ReadUint8(); - if(!patternOffset.empty()) + for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++) { - DMF_PATTERNSETTINGS settings; - settings.beat = 0; - settings.tempoTicks = 32; - settings.tempoBPM = 120; - settings.realBPMmode = false; - settings.internalTicks = 6; - settings.playDir.assign(GetNumChannels(), false); - settings.noteBuffer.assign(GetNumChannels(), NOTE_NONE); - settings.lastNote.assign(GetNumChannels(), NOTE_NONE); + chunk.ReadString<StringFixer::spacePadded>(m_szNames[smp], chunk.ReadUint8()); + DMFSampleHeader sampleHeader; + ModSample &sample = Samples[smp]; + chunk.ReadConvertEndianness(sampleHeader); + sampleHeader.ConvertToMPT(sample); - for(ORDERINDEX nOrd = 0; nOrd < Order.GetLength(); nOrd++) + if(fileHeader.version >= 8) { - // Create one pattern for each order item, as the same pattern can be played with different settings - PATTERNINDEX nPat = Order[nOrd]; - if(nPat < patternOffset.size() && patternOffset[nPat] != 0) - { - nPat = ConvertDMFPattern(lpStream + patternOffset[nPat], patternLength[nPat], settings, this); - Order[nOrd] = nPat; - // Loop end? - if(nPat != PATTERNINDEX_INVALID && nOrd == loopEnd && (loopStart > 0 || nOrd < Order.GetLength() - 1)) - { - Patterns[nPat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(loopStart)).Row(Patterns[nPat].GetNumRows() - 1).Retry(EffectWriter::rmTryPreviousRow)); - } - } + // Read library name in version 8 files + chunk.ReadString<StringFixer::spacePadded>(sample.filename, 8); } + + // We don't care for the checksum of the sample data... + chunk.Skip(sizeof(DMFSampleHeaderTail)); + + // Now read the sample data from the data chunk + FileReader sampleData = sampleDataChunk.GetChunk(sampleDataChunk.ReadUint32LE()); + if(sampleData.IsValid()) + { + SampleIO( + sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + (sampleHeader.flags & DMFSampleHeader::smpCompMask) == DMFSampleHeader::smpComp1 ? SampleIO::DMF : SampleIO::signedPCM) + .ReadSample(sample, sampleData); + } } m_nType = MOD_TYPE_DMF; @@ -1106,36 +1077,34 @@ m_nSamplePreAmp = m_nVSTiVolume = 48; return true; - - #undef ASSERT_CAN_READ_CHUNK } /////////////////////////////////////////////////////////////////////// // DMF Compression (from libmodplug) -typedef struct DMF_HNODE +struct DMFHNode { int16 left, right; uint8 value; -} DMF_HNODE; +}; -typedef struct DMF_HTREE +struct DMFHTree { const uint8 *ibuf, *ibufmax; uint32 bitbuf; int bitnum; int lastnode, nodecount; - DMF_HNODE nodes[256]; -} DMF_HTREE; + DMFHNode nodes[256]; +}; // DMF Huffman ReadBits -BYTE DMFReadBits(DMF_HTREE *tree, UINT nbits) -//------------------------------------------- +BYTE DMFReadBits(DMFHTree *tree, uint32 nbits) +//-------------------------------------------- { uint8 x = 0, bitv = 1; - while (nbits--) + while(nbits--) { if (tree->bitnum) { @@ -1156,8 +1125,8 @@ // tree: [8-bit value][12-bit index][12-bit index] = 32-bit // -void DMFNewNode(DMF_HTREE *tree) -//------------------------------ +void DMFNewNode(DMFHTree *tree) +//----------------------------- { uint8 isleft, isright; int actnode; @@ -1171,7 +1140,7 @@ if (actnode > 255) return; tree->nodecount++; tree->lastnode = tree->nodecount; - if (isleft) + if(isleft) { tree->nodes[actnode].left = (int16)tree->lastnode; DMFNewNode(tree); @@ -1180,7 +1149,7 @@ tree->nodes[actnode].left = -1; } tree->lastnode = tree->nodecount; - if (isright) + if(isright) { tree->nodes[actnode].right = (int16)tree->lastnode; DMFNewNode(tree); @@ -1191,34 +1160,32 @@ } -int DMFUnpack(LPBYTE psample, const uint8 *ibuf, const uint8 *ibufmax, UINT maxlen) -//--------------------------------------------------------------------------------- +int DMFUnpack(LPBYTE psample, const uint8 *ibuf, const uint8 *ibufmax, uint32 maxlen) +//----------------------------------------------------------------------------------- { - DMF_HTREE tree; - int actnode; - uint8 value, sign, delta = 0; + DMFHTree tree; MemsetZero(tree); tree.ibuf = ibuf; tree.ibufmax = ibufmax; DMFNewNode(&tree); - value = 0; + uint8 value = 0, delta = 0; - for (UINT i = 0; i < maxlen; i++) + for(uint32 i = 0; i < maxlen; i++) { - actnode = 0; - sign = DMFReadBits(&tree, 1); + int actnode = 0; + uint8 sign = DMFReadBits(&tree, 1); do { - if (DMFReadBits(&tree, 1)) + if(DMFReadBits(&tree, 1)) actnode = tree.nodes[actnode].right; else actnode = tree.nodes[actnode].left; - if (actnode > 255) break; + if(actnode > 255) break; delta = tree.nodes[actnode].value; - if ((tree.ibuf >= tree.ibufmax) && (!tree.bitnum)) break; + if((tree.ibuf >= tree.ibufmax) && (!tree.bitnum)) break; } while ((tree.nodes[actnode].left >= 0) && (tree.nodes[actnode].right >= 0)); - if (sign) delta ^= 0xFF; + if(sign) delta ^= 0xFF; value += delta; psample[i] = (i) ? value : 0; } Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2013-02-16 15:06:45 UTC (rev 1532) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2013-02-16 20:11:58 UTC (rev 1533) @@ -388,7 +388,7 @@ } // Read channel configuration - vector<bool> ignoreChannels(32, false); // bit set for each channel that's completely disabled + std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled m_nChannels = 0; for(CHANNELINDEX chn = 0; chn < 32; chn++) { Modified: trunk/OpenMPT/soundlib/Loaders.h =================================================================== --- trunk/OpenMPT/soundlib/Loaders.h 2013-02-16 15:06:45 UTC (rev 1532) +++ trunk/OpenMPT/soundlib/Loaders.h 2013-02-16 20:11:58 UTC (rev 1533) @@ -13,12 +13,3 @@ #include "FileReader.h" #include "Sndfile.h" #include "SampleIO.h" - -// Execute "action" if "request_bytes" bytes cannot be read from stream at position "position" -// DEPRECATED. Use FileReader instead. -#define ASSERT_CAN_READ_PROTOTYPE(position, length, request_bytes, action) \ - if((position) > (length) || (request_bytes) > (length) - (position)) action; - -// "Default" macro for checking if x bytes can be read from stream. -// DEPRECATED. Use FileReader instead. -#define ASSERT_CAN_READ(x) ASSERT_CAN_READ_PROTOTYPE(dwMemPos, dwMemLength, x, return false); Modified: trunk/OpenMPT/soundlib/SampleIO.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleIO.cpp 2013-02-16 15:06:45 UTC (rev 1532) +++ trunk/OpenMPT/soundlib/SampleIO.cpp 2013-02-16 20:11:58 UTC (rev 1533) @@ -19,7 +19,7 @@ // External decompressors extern void AMSUnpack(const char * const source, size_t sourceSize, char * const dest, const size_t destSize, char packCharacter); extern uint16 MDLReadBits(uint32 &bitbuf, uint32 &bitnum, const uint8 *(&ibuf), int8 n); -extern int DMFUnpack(LPBYTE psample, const uint8 *ibuf, const uint8 *ibufmax, UINT maxlen); +extern int DMFUnpack(LPBYTE psample, const uint8 *ibuf, const uint8 *ibufmax, uint32 maxlen); extern void ITUnpack8Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215); extern void ITUnpack16Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215); Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-16 15:06:45 UTC (rev 1532) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-16 20:11:58 UTC (rev 1533) @@ -618,7 +618,7 @@ && !ReadOKT(file) && !ReadPTM(lpStream, dwMemLength) && !ReadUlt(file) - && !ReadDMF(lpStream, dwMemLength) + && !ReadDMF(file) && !ReadDSM(lpStream, dwMemLength) && !ReadUMX(file) && !ReadAMF_Asylum(file) Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-16 15:06:45 UTC (rev 1532) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-16 20:11:58 UTC (rev 1533) @@ -404,7 +404,7 @@ bool ReadAMS2(FileReader &file); bool ReadMDL(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadOKT(FileReader &file); - bool ReadDMF(const LPCBYTE lpStream, const DWORD dwMemLength); + bool ReadDMF(FileReader &file); bool ReadPTM(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadDBM(const LPCBYTE lpStream, const DWORD dwMemLength); bool ReadAMF_Asylum(FileReader &file); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-17 21:51:32
|
Revision: 1537 http://sourceforge.net/p/modplug/code/1537 Author: saga-games Date: 2013-02-17 21:51:24 +0000 (Sun, 17 Feb 2013) Log Message: ----------- [Imp] PT1x Mode: Added ProTracker arpeggio wrap-around emulation (fixes the snare sound in doh's "Jim is dead") [Imp] IT Compatibility: Slightly changed arpeggio tick processing to be more accurate with pattern delays. [Mod] OpenMPT: Version is now 1.21.01.14 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-02-17 20:55:03 UTC (rev 1536) +++ trunk/OpenMPT/common/version.h 2013-02-17 21:51:24 UTC (rev 1537) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 13 +#define VER_MINORMINOR 14 //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/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2013-02-17 20:55:03 UTC (rev 1536) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2013-02-17 21:51:24 UTC (rev 1537) @@ -22,9 +22,6 @@ #define ENABLE_STEREOVU #endif -// Volume ramp length, in 1/10 ms -#define VOLUMERAMPLEN 0 // 1.46ms = 64 samples at 44.1kHz //rewbs.soundQ exp - was 146 - // VU-Meter #define VUMETER_DECAY 4 @@ -1151,9 +1148,9 @@ // if we are in the release portion of the envelope, // rescale envelope factor so that it is proportional to the release point // and release envelope beginning. - if (pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET + if(pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET && envpos >= pIns->VolEnv.Ticks[pIns->VolEnv.nReleaseNode] - && pChn->VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED) + && pChn->VolEnv.nEnvValueAtReleaseJump != NOT_YET_RELEASED) { int envValueAtReleaseJump = pChn->VolEnv.nEnvValueAtReleaseJump; int envValueAtReleaseNode = pIns->VolEnv.Values[pIns->VolEnv.nReleaseNode] * 4; @@ -1161,7 +1158,7 @@ //If we have just hit the release node, force the current env value //to be that of the release node. This works around the case where // we have another node at the same position as the release node. - if (envpos == pIns->VolEnv.Ticks[pIns->VolEnv.nReleaseNode]) + if(envpos == pIns->VolEnv.Ticks[pIns->VolEnv.nReleaseNode]) envval = envValueAtReleaseNode; int relativeVolumeChange = (envval - envValueAtReleaseNode) * 2; @@ -1238,8 +1235,7 @@ //is very close to original(with 12TET) when finestep count //is 15. } - } - else //Original behavior + } else //Original behavior { int l = envval; if(l < 0) @@ -1269,7 +1265,7 @@ } // Increase position - UINT position = chnEnv.nEnvPosition + (IsCompatibleMode(TRK_IMPULSETRACKER) ? 0 : 1); + uint32 position = chnEnv.nEnvPosition + (IsCompatibleMode(TRK_IMPULSETRACKER) ? 0 : 1); const InstrumentEnvelope &insEnv = pChn->pModInstrument->GetEnvelope(envType); @@ -1281,7 +1277,7 @@ if(insEnv.dwFlags[ENV_LOOP]) { // Normal loop active - UINT end = insEnv.Ticks[insEnv.nLoopEnd]; + uint32 end = insEnv.Ticks[insEnv.nLoopEnd]; if(GetType() != MOD_TYPE_XM) end++; // FT2 compatibility: If the sustain point is at the loop end and the sustain loop has been released, don't loop anymore. @@ -1324,7 +1320,7 @@ { // IT envelope processing. // Test case: EnvLoops.it - UINT start, end; + uint32 start, end; if(insEnv.dwFlags[ENV_SUSTAIN] && !pChn->dwFlags[CHN_KEYOFF]) { @@ -1513,9 +1509,11 @@ //IT playback compatibility 01 & 02 if(IsCompatibleMode(TRK_IMPULSETRACKER)) { + // Pattern delay restarts tick counting. Not quite correct yet! + const UINT tick = m_nTickCount % (m_nMusicSpeed + m_nFrameDelay); if(pChn->nArpeggio >> 4 != 0 || (pChn->nArpeggio & 0x0F) != 0) { - switch(m_nTickCount % 3) + switch(tick % 3) { case 1: period = Util::Round<int>(period / TwoToPowerXOver12(pChn->nArpeggio >> 4)); break; case 2: period = Util::Round<int>(period / TwoToPowerXOver12(pChn->nArpeggio & 0x0F)); break; @@ -1548,11 +1546,22 @@ // Other trackers else { + int note = pChn->nNote; switch(m_nTickCount % 3) { - case 1: period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio >> 4), pChn->nFineTune, pChn->nC5Speed); break; - case 2: period = GetPeriodFromNote(pChn->nNote + (pChn->nArpeggio & 0x0F), pChn->nFineTune, pChn->nC5Speed); break; + case 1: note += (pChn->nArpeggio >> 4); break; + case 2: note += (pChn->nArpeggio & 0x0F); break; } + if(note != pChn->nNote) + { + if(m_SongFlags[SONG_PT1XMODE] && note >= NOTE_MIDDLEC + 24) + { + // Weird arpeggio wrap-around in ProTracker. + // Test case: ArpWraparound.mod, and the snare sound in "Jim is dead" by doh. + note -= 37; + } + period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC5Speed); + } } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-19 02:26:16
|
Revision: 1538 http://sourceforge.net/p/modplug/code/1538 Author: saga-games Date: 2013-02-19 02:25:59 +0000 (Tue, 19 Feb 2013) Log Message: ----------- [Ref] Small changes. Modified Paths: -------------- trunk/OpenMPT/common/typedefs.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/soundlib/FileReader.h trunk/OpenMPT/soundlib/Load_mo3.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/SampleFormatConverters.h trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/WAVTools.h Modified: trunk/OpenMPT/common/typedefs.h =================================================================== --- trunk/OpenMPT/common/typedefs.h 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/common/typedefs.h 2013-02-19 02:25:59 UTC (rev 1538) @@ -56,3 +56,9 @@ const uint64 uint64_max = 18446744073709551615; typedef float float32; + +union FloatInt32 +{ + float32 f; + uint32 i; +}; Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2013-02-19 02:25:59 UTC (rev 1538) @@ -1720,8 +1720,7 @@ if(f.Open(files.first_file.c_str())) { size_t len = f.GetLength(); - const char *data = reinterpret_cast<const char *>(f.Lock(len)); - FileReader file(data, len); + FileReader file(f.Lock(len), len); errorStr = VSTPresets::GetErrorMessage(VSTPresets::LoadFile(file, *this)); f.Close(); Modified: trunk/OpenMPT/soundlib/FileReader.h =================================================================== --- trunk/OpenMPT/soundlib/FileReader.h 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/soundlib/FileReader.h 2013-02-19 02:25:59 UTC (rev 1538) @@ -34,7 +34,7 @@ // Initialize invalid file reader object. FileReader() : streamData(nullptr), streamLength(0), streamPos(0) { } // Initialize file reader object with pointer to data and data length. - FileReader(const char *data, off_t length) : streamData(data), streamLength(length), streamPos(0) { } + FileReader(const void *data, off_t length) : streamData(static_cast<const char *>(data)), streamLength(length), streamPos(0) { } // Initialize file reader object based on an existing file reader object. The other object's stream position is copied. FileReader(const FileReader &other) : streamData(other.streamData), streamLength(other.streamLength), streamPos(other.streamPos) { } @@ -285,12 +285,11 @@ // If successful, the file cursor is advanced by the size of the float. float ReadFloatLE() { - float target; + FloatInt32 target; if(Read(target)) { - uint32 temp = *reinterpret_cast<uint32 *>(&target); - SwapBytesLE(temp); - return *reinterpret_cast<float *>(&temp); + SwapBytesLE(target.i); + return target.f; } else { return 0.0f; @@ -301,12 +300,11 @@ // If successful, the file cursor is advanced by the size of the float. float ReadFloatBE() { - float target; + FloatInt32 target; if(Read(target)) { - uint32 temp = *reinterpret_cast<uint32 *>(&target); - SwapBytesBE(temp); - return *reinterpret_cast<float *>(&temp); + SwapBytesBE(target.i); + return target.f; } else { return 0.0f; @@ -394,7 +392,7 @@ // Read destSize elements of type T into a vector. // If successful, the file cursor is advanced by the size of the vector. - // Otherwise, the vector is cleared. + // Otherwise, the vector is resized to destSize, but possibly existing contents are not cleared. template<typename T> bool ReadVector(std::vector<T> &destVector, size_t destSize) { Modified: trunk/OpenMPT/soundlib/Load_mo3.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mo3.cpp 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/soundlib/Load_mo3.cpp 2013-02-19 02:25:59 UTC (rev 1538) @@ -81,7 +81,7 @@ // If decoding was successful, stream and length will keep the new pointers now. if(length > 0) { - FileReader unpackedFile(static_cast<const char *>(stream), length); + FileReader unpackedFile(stream, length); result = ReadXM(unpackedFile) || ReadIT(unpackedFile) Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2013-02-19 02:25:59 UTC (rev 1538) @@ -568,9 +568,7 @@ return false; } - //BYTE s[64*64*5]; - vector<BYTE> s(64*64*5, 0); - BYTE xmph[9]; + vector<uint8> s(64 * 64 * 5, 0); bool addChannel = false; // avoid odd channel count for FT2 compatibility XMFileHeader fileHeader; @@ -631,7 +629,7 @@ fileHeader.ConvertEndianness(); fwrite(&fileHeader, 1, sizeof(fileHeader), f); - // write order list (wihout +++ and ---, explained above) + // write order list (without +++ and ---, explained above) for(ORDERINDEX ord = 0; ord < Order.GetLengthTailTrimmed(); ord++) { if(Patterns.IsValidIndex(Order[ord]) || !compatibilityExport) @@ -642,19 +640,27 @@ } // Writing patterns - for(PATTERNINDEX pat = 0; pat < nPatterns; pat++) if (Patterns[pat]) + for(PATTERNINDEX pat = 0; pat < nPatterns; pat++) { - ModCommand *p = Patterns[pat]; + uint8 patHead[9]; + MemsetZero(patHead); + patHead[0] = 9; + patHead[5] = static_cast<uint8>(Patterns[pat].GetNumRows() & 0xFF); + patHead[6] = static_cast<uint8>(Patterns[pat].GetNumRows() >> 8); + + if(!Patterns.IsValidPat(pat)) + { + // There's nothing to write... chicken out. + fwrite(patHead, 1, 9, f); + continue; + } + + const ModCommand *p = Patterns[pat]; size_t len = 0; // Empty patterns are always loaded as 64-row patterns in FT2, regardless of their real size... bool emptyPattern = true; - MemsetZero(xmph); - xmph[0] = 9; - xmph[5] = (BYTE)(Patterns[pat].GetNumRows() & 0xFF); - xmph[6] = (BYTE)(Patterns[pat].GetNumRows() >> 8); - - for (size_t j = m_nChannels * Patterns[pat].GetNumRows(); j > 0; j--, p++) + for(size_t j = m_nChannels * Patterns[pat].GetNumRows(); j > 0; j--, p++) { // Don't write more than 32 channels if(compatibilityExport && m_nChannels - ((j - 1) % m_nChannels) > 32) continue; @@ -722,7 +728,7 @@ s[len++] = param; } else { - BYTE b = 0x80; + uint8 b = 0x80; if (note) b |= 0x01; if (p->instr) b |= 0x02; if (vol >= 0x10) b |= 0x04; @@ -751,17 +757,10 @@ len = 0; } - xmph[7] = (BYTE)(len & 0xFF); - xmph[8] = (BYTE)(len >> 8); - fwrite(xmph, 1, 9, f); + 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); - } else - { - MemsetZero(xmph); - xmph[0] = 9; - xmph[5] = (BYTE)(Patterns[pat].GetNumRows() & 0xFF); - xmph[6] = (BYTE)(Patterns[pat].GetNumRows() >> 8); - fwrite(xmph, 1, 9, f); } // Check which samples are referenced by which instruments (for assigning unreferenced samples to instruments) Modified: trunk/OpenMPT/soundlib/SampleFormatConverters.h =================================================================== --- trunk/OpenMPT/soundlib/SampleFormatConverters.h 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/soundlib/SampleFormatConverters.h 2013-02-19 02:25:59 UTC (rev 1538) @@ -254,11 +254,7 @@ template <size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex> struct ReadFloat32to16PCMandNormalize : SampleConversionFunctor<float, int16, conversionHasNoState> { - union - { - float f; - uint32 i; - } maxVal; + FloatInt32 maxVal; ReadFloat32to16PCMandNormalize() { maxVal.i = 0; } Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-19 02:25:59 UTC (rev 1538) @@ -541,7 +541,7 @@ } if (lpStream) { - FileReader file(reinterpret_cast<const char*>(lpStream), dwMemLength); + FileReader file(lpStream, dwMemLength); const std::vector<const char *> modExtensions = GetSupportedExtensions(true); @@ -562,7 +562,7 @@ { lpStream = unrar.GetOutputFile(); dwMemLength = unrar.GetOutputFileLength(); - file = FileReader((char *)lpStream, dwMemLength); + file = FileReader(lpStream, dwMemLength); } } #endif @@ -574,7 +574,7 @@ { lpStream = unlha.GetOutputFile(); dwMemLength = unlha.GetOutputFileLength(); - file = FileReader((char *)lpStream, dwMemLength); + file = FileReader(lpStream, dwMemLength); } } #endif @@ -592,7 +592,7 @@ BOOL bMMCmp = MMCMP_Unpack(&lpStream, &dwMemLength); if(bMMCmp) { - file = FileReader(reinterpret_cast<const char*>(lpStream), dwMemLength); + file = FileReader(lpStream, dwMemLength); } #endif Modified: trunk/OpenMPT/soundlib/WAVTools.h =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.h 2013-02-17 21:51:24 UTC (rev 1537) +++ trunk/OpenMPT/soundlib/WAVTools.h 2013-02-19 02:25:59 UTC (rev 1538) @@ -98,6 +98,7 @@ fmtPCM = 1, fmtFloat = 3, fmtIMA_ADPCM = 17, + fmtMP3 = 85, fmtExtensible = 0xFFFE, }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-19 02:28:50
|
Revision: 1539 http://sourceforge.net/p/modplug/code/1539 Author: saga-games Date: 2013-02-19 02:28:38 +0000 (Tue, 19 Feb 2013) Log Message: ----------- [New] Experimental support for IT-compressed samples in IT/MPTM files. To enable, set ITCompressionMono=1 and/or ITCompressionStereo=0 in mptrack.ini's [Misc] section, set ITCompressionVerification=1 to verify if samples are compressed correctly. Compressed stereo samples won't load in older versions of OpenMPT, and compressed samples will cause trouble in general with some versions (because of how the hacked-on extra info after the sample data block is searched). [Mod] OpenMPT: Version is now 1.21.01.15 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/View_tre.cpp trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/soundlib/ITTools.cpp trunk/OpenMPT/soundlib/ITTools.h trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/SampleIO.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/common/version.h 2013-02-19 02:28:38 UTC (rev 1539) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 14 +#define VER_MINORMINOR 15 //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/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -1811,13 +1811,16 @@ StringFixer::SetNullTerminator(szFileName); SanitizeFilename(szFileName); + int index = 0; FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(false, (m_pSndFile->GetType() == MOD_TYPE_XM) ? "xi" : "iti", szFileName, (m_pSndFile->GetType() == MOD_TYPE_XM) ? "FastTracker II Instruments (*.xi)|*.xi|" - "Impulse Tracker Instruments (*.iti)|*.iti||" : "Impulse Tracker Instruments (*.iti)|*.iti|" + "Compressed Impulse Tracker Instruments (*.iti)|*.iti||" : + "Impulse Tracker Instruments (*.iti)|*.iti|" + "Compressed Impulse Tracker Instruments (*.iti)|*.iti|" "FastTracker II Instruments (*.xi)|*.xi||", - CMainFrame::GetSettings().GetWorkingDirectory(DIR_INSTRUMENTS)); + CMainFrame::GetSettings().GetWorkingDirectory(DIR_INSTRUMENTS), false, &index); if(files.abort) return; BeginWaitCursor(); @@ -1825,7 +1828,7 @@ _splitpath(files.first_file.c_str(), drive, path, NULL, ext); BOOL bOk = FALSE; if (!lstrcmpi(ext, ".iti")) - bOk = m_pSndFile->SaveITIInstrument(m_nInstrument, files.first_file.c_str()); + bOk = m_pSndFile->SaveITIInstrument(m_nInstrument, files.first_file.c_str(), index == (m_pSndFile->GetType() == MOD_TYPE_XM ? 3 : 2)); else bOk = m_pSndFile->SaveXIInstrument(m_nInstrument, files.first_file.c_str()); Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -513,7 +513,7 @@ const bool xi = _stricmp(&m_SndFile.m_szInstrumentPath[i][len - 2],"xi") == 0; if(iti || (!iti && !xi && m_SndFile.m_nType & (MOD_TYPE_IT|MOD_TYPE_MPT))) - m_SndFile.SaveITIInstrument(i+1, m_SndFile.m_szInstrumentPath[i]); + m_SndFile.SaveITIInstrument(i+1, m_SndFile.m_szInstrumentPath[i], false); if(xi || (!xi && !iti && m_SndFile.m_nType == MOD_TYPE_XM)) m_SndFile.SaveXIInstrument(i+1, m_SndFile.m_szInstrumentPath[i]); } @@ -2106,10 +2106,10 @@ if(pat != PATTERNINDEX_INVALID) { ORDERINDEX ord = 0; - for(ORDERINDEX i = 0; i < m_SndFile.Order.size(); i++) + for (ORDERINDEX i = 0; i < m_SndFile.Order.size(); i++) { - if(m_SndFile.Order[i] == pat) ord = i; - if(m_SndFile.Order[i] == m_SndFile.Order.GetInvalidPatIndex()) break; + if (m_SndFile.Order[i] == pat) ord = i; + if (m_SndFile.Order[i] == m_SndFile.Order.GetInvalidPatIndex()) break; } ViewPattern(pat, ord); } @@ -2120,7 +2120,7 @@ //---------------------------- { SAMPLEINDEX smp = InsertSample(); - if(smp != SAMPLEINDEX_INVALID) ViewSample(smp); + if (smp != SAMPLEINDEX_INVALID) ViewSample(smp); } @@ -2128,7 +2128,7 @@ //-------------------------------- { INSTRUMENTINDEX ins = InsertInstrument(); - if(ins != INSTRUMENTINDEX_INVALID) ViewInstrument(ins); + if (ins != INSTRUMENTINDEX_INVALID) ViewInstrument(ins); } Modified: trunk/OpenMPT/mptrack/View_tre.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_tre.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/mptrack/View_tre.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -1584,7 +1584,7 @@ //------------------------------------ { TV_INSERTSTRUCT tvis; - CHAR s[_MAX_PATH+32], szPath[_MAX_PATH] = ""; + char s[_MAX_PATH+32], szPath[_MAX_PATH] = ""; if (!m_hInsLib) return; SetRedraw(FALSE); @@ -1716,7 +1716,7 @@ const size_t len = strlen(s); for(size_t i = 0; i < len; i++) { - s[i] = tolower(s[i + 1]); + s[i] = (char)tolower(s[i + 1]); } } @@ -3190,7 +3190,7 @@ BOOL xi = _stricmp(&pSndFile->m_szInstrumentPath[modItemID - 1][size-2],"xi") == 0; if(iti || (!iti && !xi && pSndFile->m_nType & (MOD_TYPE_IT|MOD_TYPE_MPT))) - pSndFile->SaveITIInstrument((INSTRUMENTINDEX)modItemID, pSndFile->m_szInstrumentPath[modItemID - 1]); + pSndFile->SaveITIInstrument((INSTRUMENTINDEX)modItemID, pSndFile->m_szInstrumentPath[modItemID - 1], false); if(xi || (!xi && !iti && pSndFile->m_nType == MOD_TYPE_XM)) pSndFile->SaveXIInstrument((INSTRUMENTINDEX)modItemID, pSndFile->m_szInstrumentPath[modItemID - 1]); Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-02-19 02:28:38 UTC (rev 1539) @@ -489,6 +489,10 @@ > </File> <File + RelativePath="..\soundlib\ITCompression.cpp" + > + </File> + <File RelativePath="..\common\serialization_utils.cpp" > </File> @@ -1031,6 +1035,10 @@ > </File> <File + RelativePath="..\soundlib\ITCompression.h" + > + </File> + <File RelativePath="..\common\serialization_utils.h" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-02-19 02:28:38 UTC (rev 1539) @@ -172,6 +172,7 @@ <ClCompile Include="..\common\AudioCriticalSection.cpp" /> <ClCompile Include="..\common\misc_util.cpp" /> <ClCompile Include="..\common\Reporting.cpp" /> + <ClCompile Include="..\soundlib\ITCompression.cpp" /> <ClCompile Include="..\soundlib\ITTools.cpp" /> <ClCompile Include="..\soundlib\MIDIEvents.cpp" /> <ClCompile Include="..\soundlib\MIDIMacros.cpp" /> @@ -329,6 +330,7 @@ <ClInclude Include="..\common\typedefs.h" /> <ClInclude Include="..\soundlib\ChunkReader.h" /> <ClInclude Include="..\soundlib\FileReader.h" /> + <ClInclude Include="..\soundlib\ITCompression.h" /> <ClInclude Include="..\soundlib\ITTools.h" /> <ClInclude Include="..\soundlib\MIDIEvents.h" /> <ClInclude Include="..\soundlib\MIDIMacros.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-02-19 02:28:38 UTC (rev 1539) @@ -424,6 +424,9 @@ <ClCompile Include="VstPresets.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\soundlib\ITCompression.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -753,6 +756,9 @@ <ClInclude Include="VstPresets.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\soundlib\ITCompression.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Modified: trunk/OpenMPT/soundlib/ITTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITTools.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/soundlib/ITTools.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -467,8 +467,8 @@ // Convert OpenMPT's internal sample representation to an ITSample. -void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType) -//------------------------------------------------------------------- +void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215) +//------------------------------------------------------------------------------------------------------ { MemsetZero(*this); @@ -502,6 +502,15 @@ flags |= ITSample::sample16Bit; } cvt = ITSample::cvtSignedSample; + + if(compress) + { + flags |= ITSample::sampleCompressed; + if(compressIT215) + { + cvt |= ITSample::cvtIT215Compression; + } + } } else { flags = 0x00; Modified: trunk/OpenMPT/soundlib/ITTools.h =================================================================== --- trunk/OpenMPT/soundlib/ITTools.h 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/soundlib/ITTools.h 2013-02-19 02:28:38 UTC (rev 1539) @@ -291,7 +291,7 @@ void ConvertEndianness(); // Convert OpenMPT's internal sample representation to an ITSample. - void ConvertToIT(const ModSample &mptSmp, MODTYPE fromType); + void ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215); // Convert an ITSample to OpenMPT's internal sample representation. size_t ConvertToMPT(ModSample &mptSmp) const; // Retrieve the internal sample format flags for this instrument. Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -651,16 +651,12 @@ } // Load instrument and song extensions. - if(mptStartPos >= file.GetPosition()) + LoadExtendedInstrumentProperties(file, &interpretModPlugMade); + if(interpretModPlugMade) { - if(interpretModPlugMade) - { - m_nMixLevels = mixLevels_original; - } - FileReader chunk = file.GetChunk(mptStartPos - file.GetPosition()); - LoadExtendedInstrumentProperties(chunk, &interpretModPlugMade); - LoadExtendedSongProperties(GetType(), chunk, &interpretModPlugMade); + m_nMixLevels = mixLevels_original; } + LoadExtendedSongProperties(GetType(), file, &interpretModPlugMade); const PATTERNINDEX numPats = Util::Min(static_cast<PATTERNINDEX>(patPos.size()), GetModSpecifications().patternsMax); @@ -859,7 +855,7 @@ // 0-64: Set Volume if(vol <= 64) { m[ch].volcmd = VOLCMD_VOLUME; m[ch].vol = vol; } else // 128-192: Set Panning - if((vol >= 128) && (vol <= 192)) { m[ch].volcmd = VOLCMD_PANNING; m[ch].vol = vol - 128; } else + if(vol >= 128 && vol <= 192) { m[ch].volcmd = VOLCMD_PANNING; m[ch].vol = vol - 128; } else // 65-74: Fine Volume Up if(vol < 75) { m[ch].volcmd = VOLCMD_FINEVOLUP; m[ch].vol = vol - 65; } else // 75-84: Fine Volume Down @@ -873,18 +869,18 @@ // 115-124: Pitch Slide Down if(vol < 125) { m[ch].volcmd = VOLCMD_PORTAUP; m[ch].vol = vol - 115; } else // 193-202: Portamento To - if((vol >= 193) && (vol <= 202)) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else + 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)) + 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)) + // Old versions of ModPlug saved this as vibrato speed instead, so let's fix that. + if(m[ch].vol && m_dwLastSavedWithVersion && m_dwLastSavedWithVersion <= MAKE_VERSION_NUMERIC(1, 17, 02, 54)) m[ch].volcmd = VOLCMD_VIBRATOSPEED; } else // 213-222: Unused (was velocity) // 223-232: Offset - if((vol >= 223) && (vol <= 232)) { m[ch].volcmd = VOLCMD_OFFSET; m[ch].vol = vol - 223; } + if(vol >= 223 && vol <= 232) { m[ch].volcmd = VOLCMD_OFFSET; m[ch].vol = vol - 223; } lastValue[ch].volcmd = m[ch].volcmd; lastValue[ch].vol = m[ch].vol; } @@ -1027,6 +1023,9 @@ #pragma warning(disable:4100) +#ifdef MODPLUG_TRACKER +#include "../mptrack/Mptrack.h" // For config filename +#endif // MODPLUG_TRACKER bool CSoundFile::SaveIT(LPCSTR lpszFileName, bool compatibilityExport) //-------------------------------------------------------------------- @@ -1069,9 +1068,9 @@ itHeader.patnum = min(Patterns.GetNumPatterns(), specs.patternsMax); // Parapointers - vector<DWORD> patpos(itHeader.patnum, 0); - vector<DWORD> smppos(itHeader.smpnum, 0); - vector<DWORD> inspos(itHeader.insnum, 0); + vector<uint32> patpos(itHeader.patnum, 0); + vector<uint32> smppos(itHeader.smpnum, 0); + vector<uint32> inspos(itHeader.insnum, 0); //VERSION if(GetType() == MOD_TYPE_MPT) @@ -1482,7 +1481,13 @@ // Writing Sample Data for (UINT nsmp=1; nsmp<=itHeader.smpnum; nsmp++) { - itss.ConvertToIT(Samples[nsmp], GetType()); +#ifdef MODPLUG_TRACKER + bool compress = ::GetPrivateProfileInt("Misc", Samples[nsmp].GetNumChannels() > 1 ? "ITCompressionStereo" : "ITCompressionMono", 0, theApp.GetConfigFileName()) != 0; +#else + bool compress = false; +#endif + // Old MPT will only consider the IT2.15 compression flag if the header version also indicates IT2.15. + itss.ConvertToIT(Samples[nsmp], GetType(), compress, itHeader.cmwt >= 0x215); StringFixer::WriteString<StringFixer::nullTerminated>(itss.name, m_szNames[nsmp]); @@ -1569,196 +1574,6 @@ #endif // MODPLUG_NO_FILESAVE -////////////////////////////////////////////////////////////////////////////// -// IT 2.14 compression - -DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, const uint8 *(&ibuf), CHAR n) -//------------------------------------------------------------------------- -{ - DWORD retval = 0; - UINT i = n; - - if (n > 0) - { - do - { - if (!bitnum) - { - bitbuf = *ibuf++; - bitnum = 8; - } - retval >>= 1; - retval |= bitbuf << 31; - bitbuf >>= 1; - bitnum--; - i--; - } while (i); - i = n; - } - return (retval >> (32-i)); -} - - -void ITUnpack8Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215) -//-------------------------------------------------------------------------------------------------- -{ - LPSTR pDst = pSample; - const uint8 *pSrc = lpMemFile; - DWORD wHdr = 0; - DWORD wCount = 0; - DWORD bitbuf = 0; - UINT bitnum = 0; - BYTE bLeft = 0, bTemp = 0, bTemp2 = 0; - - while (dwLen) - { - if (!wCount) - { - wCount = 0x8000; - wHdr = *((LPWORD)pSrc); - pSrc += 2; - bLeft = 9; - bTemp = bTemp2 = 0; - bitbuf = bitnum = 0; - } - DWORD d = wCount; - if (d > dwLen) d = dwLen; - // Unpacking - DWORD dwPos = 0; - do - { - WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, bLeft); - if (bLeft < 7) - { - DWORD i = 1 << (bLeft-1); - DWORD j = wBits & 0xFFFF; - if (i != j) goto UnpackByte; - wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, 3) + 1) & 0xFF; - bLeft = ((BYTE)wBits < bLeft) ? (BYTE)wBits : (BYTE)((wBits+1) & 0xFF); - goto Next; - } - if (bLeft < 9) - { - WORD i = (0xFF >> (9 - bLeft)) + 4; - WORD j = i - 8; - if ((wBits <= j) || (wBits > i)) goto UnpackByte; - wBits -= j; - bLeft = ((BYTE)(wBits & 0xFF) < bLeft) ? (BYTE)(wBits & 0xFF) : (BYTE)((wBits+1) & 0xFF); - goto Next; - } - if (bLeft >= 10) goto SkipByte; - if (wBits >= 256) - { - bLeft = (BYTE)(wBits + 1) & 0xFF; - goto Next; - } - UnpackByte: - if (bLeft < 8) - { - BYTE shift = 8 - bLeft; - char c = (char)(wBits << shift); - c >>= shift; - wBits = (WORD)c; - } - wBits += bTemp; - bTemp = (BYTE)wBits; - bTemp2 += bTemp; - pDst[dwPos] = (it215) ? bTemp2 : bTemp; - - SkipByte: - dwPos++; - Next: - if (pSrc >= lpMemFile+dwMemLength+1) return; - } while (dwPos < d); - // Move On - wCount -= d; - dwLen -= d; - pDst += d; - } -} - - -void ITUnpack16Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215) -//--------------------------------------------------------------------------------------------------- -{ - signed short *pDst = (signed short *)pSample; - const uint8 *pSrc = lpMemFile; - DWORD wHdr = 0; - DWORD wCount = 0; - DWORD bitbuf = 0; - UINT bitnum = 0; - BYTE bLeft = 0; - signed short wTemp = 0, wTemp2 = 0; - - while (dwLen) - { - if (!wCount) - { - wCount = 0x4000; - wHdr = *((LPWORD)pSrc); - pSrc += 2; - bLeft = 17; - wTemp = wTemp2 = 0; - bitbuf = bitnum = 0; - } - DWORD d = wCount; - if (d > dwLen) d = dwLen; - // Unpacking - DWORD dwPos = 0; - do - { - DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, bLeft); - if (bLeft < 7) - { - DWORD i = 1 << (bLeft-1); - DWORD j = dwBits; - if (i != j) goto UnpackByte; - dwBits = ITReadBits(bitbuf, bitnum, pSrc, 4) + 1; - bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF); - goto Next; - } - if (bLeft < 17) - { - DWORD i = (0xFFFF >> (17 - bLeft)) + 8; - DWORD j = (i - 16) & 0xFFFF; - if ((dwBits <= j) || (dwBits > (i & 0xFFFF))) goto UnpackByte; - dwBits -= j; - bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF); - goto Next; - } - if (bLeft >= 18) goto SkipByte; - if (dwBits >= 0x10000) - { - bLeft = (BYTE)(dwBits + 1) & 0xFF; - goto Next; - } - UnpackByte: - if (bLeft < 16) - { - BYTE shift = 16 - bLeft; - signed short c = (signed short)(dwBits << shift); - c >>= shift; - dwBits = (DWORD)c; - } - dwBits += wTemp; - wTemp = (signed short)dwBits; - wTemp2 += wTemp; - pDst[dwPos] = (it215) ? wTemp2 : wTemp; - - SkipByte: - dwPos++; - Next: - if (pSrc >= lpMemFile+dwMemLength+1) return; - } while (dwPos < d); - // Move On - wCount -= d; - dwLen -= d; - pDst += d; - if (pSrc >= lpMemFile+dwMemLength) break; - } -} - - #ifndef MODPLUG_NO_FILESAVE UINT CSoundFile::SaveMixPlugins(FILE *f, BOOL bUpdate) Modified: trunk/OpenMPT/soundlib/Load_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -449,7 +449,7 @@ if(!sampleUsed[nsmp - 1] && Samples[nsmp].pSample) { ITSample itss; - itss.ConvertToIT(Samples[nsmp], GetType()); + itss.ConvertToIT(Samples[nsmp], GetType(), false, false); StringFixer::WriteString<StringFixer::nullTerminated>(itss.name, m_szNames[nsmp]); Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -28,7 +28,7 @@ bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength) //-------------------------------------------------------------------------------------------------- { - FileReader file(reinterpret_cast<const char *>(lpMemFile), dwFileLength); + FileReader file(lpMemFile, dwFileLength); if(!nSample || nSample >= MAX_SAMPLES) return false; if(!ReadWAVSample(nSample, file) && !ReadXISample(nSample, file) @@ -55,7 +55,7 @@ bool CSoundFile::ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength) //--------------------------------------------------------------------------------------------------------- { - FileReader file(reinterpret_cast<const char *>(lpMemFile), dwFileLength); + FileReader file(lpMemFile, dwFileLength); if ((!nInstr) || (nInstr >= MAX_INSTRUMENTS)) return false; if ((!ReadXIInstrument(nInstr, file)) && (!ReadPATInstrument(nInstr, lpMemFile, dwFileLength)) @@ -84,6 +84,7 @@ || psig[0] == LittleEndian('CaLf') // FLAC signature #endif // NO_FLAC #ifndef NO_MP3_SAMPLES + || (lpMemFile[0] == 0xFF && lpMemFile[1] == 0xFB) // MP2 signature || (lpMemFile[0] == 0xFF && lpMemFile[1] == 0xFB) // MP3 signature || (lpMemFile[0] == 'I' && lpMemFile[1] == 'D' && lpMemFile[2] == '3') // MP3 signature #endif // NO_MP3_SAMPLES @@ -318,9 +319,9 @@ if(!wavFile.IsValid() || wavFile.GetNumChannels() == 0 || wavFile.GetNumChannels() > 2 - || wavFile.GetBitsPerSample() == 0 + || (wavFile.GetBitsPerSample() == 0 && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3) || wavFile.GetBitsPerSample() > 32 - || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat && wavFile.GetSampleFormat() != WAVFormatChunk::fmtIMA_ADPCM)) + || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat && wavFile.GetSampleFormat() != WAVFormatChunk::fmtIMA_ADPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtMP3)) { return false; } @@ -347,6 +348,10 @@ } IMAADPCMUnpack16((int16 *)sample.pSample, sample.nLength, sampleChunk.GetRawData(), sampleChunk.BytesLeft(), wavFile.GetBlockAlign()); AdjustSampleLoop(sample); + } else if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtMP3) + { + // MP3 in WAV + return ReadMP3Sample(nSample, sampleChunk); } else { // PCM / Float @@ -1579,12 +1584,11 @@ } -bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const LPCSTR lpszFileName) const -//----------------------------------------------------------------------------------------- +bool CSoundFile::SaveITIInstrument(INSTRUMENTINDEX nInstr, const LPCSTR lpszFileName, bool compress) const +//-------------------------------------------------------------------------------------------------------- { ITInstrumentEx iti; ModInstrument *pIns = Instruments[nInstr]; - uint32 filePos; FILE *f; if((!pIns) || (!lpszFileName)) return false; @@ -1614,39 +1618,33 @@ } smpmap.clear(); - filePos = instSize; + uint32 filePos = instSize; iti.ConvertEndianness(); fwrite(&iti, 1, instSize, f); filePos += smptable.size() * sizeof(ITSample); - // Writing sample headers + // Writing sample headers + data + vector<SampleIO> sampleFlags; for(vector<SAMPLEINDEX>::iterator iter = smptable.begin(); iter != smptable.end(); iter++) { ITSample itss; - itss.ConvertToIT(Samples[*iter], GetType()); + itss.ConvertToIT(Samples[*iter], GetType(), compress, compress); StringFixer::WriteString<StringFixer::nullTerminated>(itss.name, m_szNames[*iter]); itss.samplepointer = filePos; itss.ConvertEndianness(); fwrite(&itss, 1, sizeof(itss), f); - filePos += Samples[*iter].GetSampleSizeInBytes(); - } - // Writing Sample Data - for(vector<SAMPLEINDEX>::iterator iter = smptable.begin(); iter != smptable.end(); iter++) - { - const ModSample &sample = Samples[*iter]; - // TODO we should actually use ITSample::GetSampleFormat() instead of re-computing the flags here. - SampleIO( - (sample.uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, - (sample.uFlags & CHN_STEREO) ? SampleIO::stereoSplit : SampleIO::mono, - SampleIO::littleEndian, - SampleIO::signedPCM) - .WriteSample(f, sample); + // Write sample + off_t curPos = ftell(f); + fseek(f, filePos, SEEK_SET); + filePos += itss.GetSampleFormat(0x0214).WriteSample(f, Samples[*iter]); + fseek(f, curPos, SEEK_SET); } + fseek(f, 0, SEEK_END); int32 code = 'MPTX'; SwapBytesLE(code); fwrite(&code, 1, sizeof(int32), f); // Write extension tag Modified: trunk/OpenMPT/soundlib/SampleIO.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleIO.cpp 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/soundlib/SampleIO.cpp 2013-02-19 02:28:38 UTC (rev 1539) @@ -14,14 +14,13 @@ #include "Loaders.h" #include "SampleIO.h" #include "SampleFormatConverters.h" +#include "ITCompression.h" // External decompressors extern void AMSUnpack(const char * const source, size_t sourceSize, char * const dest, const size_t destSize, char packCharacter); extern uint16 MDLReadBits(uint32 &bitbuf, uint32 &bitnum, const uint8 *(&ibuf), int8 n); extern int DMFUnpack(LPBYTE psample, const uint8 *ibuf, const uint8 *ibufmax, uint32 maxlen); -extern void ITUnpack8Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215); -extern void ITUnpack16Bit(LPSTR pSample, DWORD dwLen, const uint8 *lpMemFile, DWORD dwMemLength, bool it215); // Read a sample from memory @@ -294,17 +293,9 @@ } else if(GetEncoding() == IT214 || GetEncoding() == IT215) { // IT 2.14 / 2.15 compressed samples - if(fileSize > 4) - { - bytesRead = fileSize; - if(GetBitDepth() == 8) - { - ITUnpack8Bit(sample.pSample, sample.nLength, sourceBuf, fileSize, GetEncoding() == IT215); - } else if(GetBitDepth() == 16) - { - ITUnpack16Bit(sample.pSample, sample.nLength, sourceBuf, fileSize, GetEncoding() == IT215); - } - } + size_t startPos = file.GetPosition(); + ITDecompression(file, sample, GetEncoding() == IT215); + bytesRead = file.GetPosition() - startPos; } else if(GetEncoding() == AMS && GetChannelFormat() == mono) { // AMS compressed samples @@ -531,6 +522,13 @@ if (bufcount) if(f) fwrite(buffer, 1, bufcount, f); } + else if(GetEncoding() == IT214 || GetEncoding() == IT215) + { + // IT2.14-encoded samples + ITCompression its(sample, GetEncoding() == IT215, f); + len = its.GetCompressedSize(); + } + // Default: assume 8-bit PCM data else { Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-19 02:25:59 UTC (rev 1538) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-19 02:28:38 UTC (rev 1539) @@ -648,7 +648,7 @@ bool ReadPATInstrument(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); bool ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); bool SaveXIInstrument(INSTRUMENTINDEX nInstr, const LPCSTR lpszFileName) const; - bool SaveITIInstrument(INSTRUMENTINDEX nInstr, const LPCSTR lpszFileName) const; + bool SaveITIInstrument(INSTRUMENTINDEX nInstr, const LPCSTR lpszFileName, bool compress) const; // I/O from another sound file bool ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoundFile *pSrcSong, INSTRUMENTINDEX sourceInstr); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-21 15:23:08
|
Revision: 1543 http://sourceforge.net/p/modplug/code/1543 Author: saga-games Date: 2013-02-21 15:22:57 +0000 (Thu, 21 Feb 2013) Log Message: ----------- [Imp] When clicking the "MIDI Record" button and the device is not ready, opening the device is now tried again after the popup settings dialog is closed. [Imp] VST: Current program name is now suggested when saving FXP files. [Ref] Smaller changes. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mpt_midi.cpp trunk/OpenMPT/mptrack/Mptrack.cpp trunk/OpenMPT/mptrack/VstPresets.cpp trunk/OpenMPT/mptrack/VstPresets.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/soundlib/Dlsbank.cpp trunk/OpenMPT/soundlib/ITCompression.cpp trunk/OpenMPT/soundlib/ITCompression.h Modified: trunk/OpenMPT/mptrack/Mpt_midi.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mpt_midi.cpp 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/mptrack/Mpt_midi.cpp 2013-02-21 15:22:57 UTC (rev 1543) @@ -123,7 +123,7 @@ if (shMidiIn) return TRUE; try { - if (midiInOpen(&shMidiIn, GetSettings().m_nMidiDevice, (DWORD)MidiInCallBack, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + if (midiInOpen(&shMidiIn, GetSettings().m_nMidiDevice, (DWORD_PTR)MidiInCallBack, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { shMidiIn = NULL; @@ -131,7 +131,12 @@ CMainFrame::m_nLastOptionsPage = OPTIONS_PAGE_MIDI; CMainFrame::GetMainFrame()->OnViewOptions(); - return FALSE; + // Let's see if the user updated the settings. + if(midiInOpen(&shMidiIn, GetSettings().m_nMidiDevice, (DWORD_PTR)MidiInCallBack, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + { + shMidiIn = NULL; + return FALSE; + } } midiInStart(shMidiIn); } catch (...) {} Modified: trunk/OpenMPT/mptrack/Mptrack.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-21 15:22:57 UTC (rev 1543) @@ -1625,6 +1625,8 @@ "http://www.hermannseib.com/english/vsthost.htm|" "Ian Luck for UNMO3|" "http://www.un4seen.com/mo3.html|" + "Ben \"GreaseMonkey\" Russell for IT sample compression code|" + "https://github.com/iamgreaser/it2everything/|" "Jean-loup Gailly and Mark Adler for zlib|" "http://zlib.net/|" "Josh Coalson for libFLAC|" Modified: trunk/OpenMPT/mptrack/VstPresets.cpp =================================================================== --- trunk/OpenMPT/mptrack/VstPresets.cpp 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/mptrack/VstPresets.cpp 2013-02-21 15:22:57 UTC (rev 1543) @@ -234,11 +234,7 @@ void VSTPresets::WriteBE(float v, std::ostream &f) //------------------------------------------------ { - union - { - float f; - uint32 i; - } u; + FloatInt32 u; u.f = v; WriteBE(u.i, f); } Modified: trunk/OpenMPT/mptrack/VstPresets.h =================================================================== --- trunk/OpenMPT/mptrack/VstPresets.h 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/mptrack/VstPresets.h 2013-02-21 15:22:57 UTC (rev 1543) @@ -44,6 +44,6 @@ #else static ErrorCode LoadFile(FileReader &, CVstPlugin &) { return invalidFile; } static bool SaveFile(std::ostream &, CVstPlugin &, bool) { return false; } - static const char *GetErrorMessage(ErrorCode); + static const char *GetErrorMessage(ErrorCode) { return nullptr; } #endif // NO_VST }; Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2013-02-21 15:22:57 UTC (rev 1543) @@ -1664,7 +1664,11 @@ defaultDir = defaultDir.substr(0, defaultDir.find_last_of("\\/")); } - FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(false, "fxp", "", + char rawname[max(kVstMaxProgNameLen + 1, 256)] = ""; // kVstMaxProgNameLen is 24... + Dispatch(effGetProgramName, 0, 0, rawname, 0); + SanitizeFilename(rawname); + StringFixer::SetNullTerminator(rawname); + FileDlgResult files = CTrackApp::ShowOpenSaveFileDialog(false, "fxp", rawname, "VST Plugin Programs (*.fxp)|*.fxp|" "VST Plugin Banks (*.fxb)|*.fxb||", defaultDir); Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp =================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.cpp 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/soundlib/Dlsbank.cpp 2013-02-21 15:22:57 UTC (rev 1543) @@ -1517,7 +1517,7 @@ bWaveForm = (sample.pSample) ? TRUE : FALSE; } else { - FileReader file(reinterpret_cast<const char *>(pWaveForm), dwLen); + FileReader file(pWaveForm, dwLen); bWaveForm = pSndFile->ReadWAVSample(nSample, file, &wsmpChunk); } if (bWaveForm) Modified: trunk/OpenMPT/soundlib/ITCompression.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITCompression.cpp 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/soundlib/ITCompression.cpp 2013-02-21 15:22:57 UTC (rev 1543) @@ -144,18 +144,18 @@ { if(width <= 6) { - // Mode A + // Mode A: 1 to 6 bits ASSERT(width); WriteBits(width, (1 << (width - 1))); WriteBits(Properties::fetchA, ConvertWidth(width, bwt[i])); } else if(width < Properties::defWidth) { - // Mode B + // Mode B: 7 to 8 / 16 bits int xv = (1 << (width - 1)) + Properties::lowerB + ConvertWidth(width, bwt[i]); WriteBits(width, xv); } else { - // Mode C + // Mode C: 9 / 17 bits ASSERT((bwt[i] - 1) >= 0); WriteBits(width, (1 << (width - 1)) + bwt[i] - 1); } @@ -355,6 +355,12 @@ { chunk = file.GetChunk(file.ReadUint16LE()); + // Initialise bit reader + dataPos = 0; + bitPos = 0; + remBits = 8; + mem1 = mem2 = 0; + if(mptSample.GetElementarySampleSize() > 1) Uncompress<IT16BitParams>(mptSample.pSample + 2 * chn); else @@ -368,12 +374,6 @@ void ITDecompression::Uncompress(void *target) //-------------------------------------------- { - // Initialise bit reader - dataPos = 0; - bitPos = 0; - remBits = 8; - mem1 = mem2 = 0; - curLength = Util::Min(mptSample.nLength - writtenSamples, SmpLength(ITCompression::blockSize / sizeof(Properties::sample_t))); int width = Properties::defWidth; @@ -389,21 +389,21 @@ const int topBit = (1 << (width - 1)); if(width <= 6) { - // Mode A + // Mode A: 1 to 6 bits if(v == topBit) ChangeWidth(width, ReadBits(Properties::fetchA)); else Write<Properties>(v, topBit, target); } else if(width < Properties::defWidth) { - // Mode B + // Mode B: 7 to 8 / 16 bits if(v >= topBit + Properties::lowerB && v <= topBit + Properties::upperB) ChangeWidth(width, v - (topBit + Properties::lowerB)); else Write<Properties>(v, topBit, target); } else { - // Mode C + // Mode C: 9 / 17 bits if(v & topBit) width = (v & ~topBit) + 1; else Modified: trunk/OpenMPT/soundlib/ITCompression.h =================================================================== --- trunk/OpenMPT/soundlib/ITCompression.h 2013-02-19 18:40:54 UTC (rev 1542) +++ trunk/OpenMPT/soundlib/ITCompression.h 2013-02-21 15:22:57 UTC (rev 1543) @@ -1,6 +1,6 @@ /* - * ITCompression.cpp - * ----------------- + * ITCompression.h + * --------------- * Purpose: Code for IT sample compression and decompression. * Notes : The original Python compression code was written by GreaseMonkey and has been released into the public domain. * Authors: OpenMPT Devs @@ -74,15 +74,18 @@ ITDecompression(FileReader &file, ModSample &sample, bool it215); protected: - FileReader chunk; - ModSample &mptSample; + FileReader chunk; // Currnetly processed block + ModSample &mptSample; // Sample that is being processed + SmpLength writtenSamples; // Number of samples so far written on this channel + SmpLength writePos; // Absolut write position in sample (for stereo samples) + SmpLength curLength; // Length of currently processed block + FileReader::off_t dataPos; // Position in input block + int mem1, mem2; // Integrator memory + // Bit reader - SmpLength writtenSamples, writePos, curLength; - FileReader::off_t dataPos; - int mem1, mem2; - int bitPos; - int remBits; + int bitPos; // Current bit position in this byte + int remBits; // Remaining bits in this byte bool is215; // Use IT2.15 compression (double deltas) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-02-21 15:25:05
|
Revision: 1544 http://sourceforge.net/p/modplug/code/1544 Author: saga-games Date: 2013-02-21 15:24:54 +0000 (Thu, 21 Feb 2013) Log Message: ----------- [Imp] Further improvements in the M15 loader - sample loops, volume commands with values > 7F, Dxx heuristic [Mod] OpenMPT: Version is now 1.21.01.16 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/soundlib/Load_mod.cpp Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-02-21 15:22:57 UTC (rev 1543) +++ trunk/OpenMPT/common/version.h 2013-02-21 15:24:54 UTC (rev 1544) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 15 +#define VER_MINORMINOR 16 //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_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-21 15:22:57 UTC (rev 1543) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2013-02-21 15:24:54 UTC (rev 1544) @@ -230,7 +230,7 @@ SmpLength lStart = loopStart * 2; SmpLength lLength = loopLength * 2; - // Fix loops + // See if loop start is incorrect as words, but correct as bytes (like in Soundtracker modules) if(lLength > 2 && (lStart + lLength > mptSmp.nLength) && (lStart / 2 + lLength <= mptSmp.nLength)) { @@ -375,15 +375,15 @@ file.ReadConvertEndianness(sampleHeader); sampleHeader.ConvertToMPT(sample); + StringFixer::ReadString<StringFixer::spacePadded>(sampleName, sampleHeader.name); // Get rid of weird characters in sample names. - for(size_t i = 0; i < CountOf(sampleHeader.name); i++) + for(size_t i = 0; i < CountOf(sampleName); i++) { - if(sampleHeader.name[i] && sampleHeader.name[i] < ' ') + if(sampleName[i] && sampleName[i] < ' ') { - sampleHeader.name[i] = ' '; + sampleName[i] = ' '; } } - StringFixer::ReadString<StringFixer::spacePadded>(sampleName, sampleHeader.name); } @@ -421,14 +421,11 @@ const size_t patternStartOffset = file.GetPosition(); const size_t sizeWithoutPatterns = totalSampleLen + patternStartOffset; - if(checkForWOW) + // Check if this is a Mod's Grave WOW file... Never seen one of those, but apparently they *do* exist. + // Basically, WOW files seem to use the M.K. extensions, but are actually 8CHN files. + if(checkForWOW && sizeWithoutPatterns + numPatterns * 8 * 256 == file.GetLength()) { - // Check if this is a Mod's Grave WOW file... Never seen one of those, but apparently they *do* exist. - // Basically, WOW files seem to use the M.K. extensions, but are actually 8CHN files. - if(sizeWithoutPatterns + numPatterns * 8 * 256 == file.GetLength()) - { - numChannels = 8; - } + numChannels = 8; } // Now we have to check if the "hidden" patterns in the order list are actually real, i.e. if they are saved in the file. @@ -637,7 +634,7 @@ for(ROWINDEX row = 0; row < 64; row++) { // FLT8: either write to channel 1 to 4 (even patterns) or 5 to 8 (odd patterns). - ModCommand *rowBase = Patterns[actualPattern].GetpModCommand(row, ((pat % 2u) == 0 || !isFLT8) ? 0 : 4); + PatternRow rowBase = Patterns[actualPattern].GetpModCommand(row, ((pat % 2u) == 0 || !isFLT8) ? 0 : 4); for(CHANNELINDEX chn = 0; chn < readChannels; chn++) { @@ -787,6 +784,11 @@ hasDiskNames = false; } + // Loop start is always in bytes, not words, so don't trust the auto-fix magic in the sample header conversion (fixes loop of "st-01:asia" in mod.drag 10) + Samples[smp].nLoopStart = sampleHeader.loopStart; + Samples[smp].nLoopEnd = sampleHeader.loopStart + sampleHeader.loopLength * 2; + Samples[smp].SanitizeLoops(); + // UST only handles samples up to 9999 bytes. Master Soundtracker 1.0 and SoundTracker 2.0 introduce 32KB samples. if(sampleHeader.length > 4999 || sampleHeader.loopStart > 9999) { @@ -859,11 +861,25 @@ FileReader::off_t patOffset = file.GetPosition(); // Scan patterns to identify Ultimate Soundtracker modules. + uint8 emptyCmds = 0; for(size_t i = 0; i < numPatterns * 64u * 4u; i++) { uint8 data[4]; file.ReadArray(data); const uint8 eff = data[2] & 0x0F, param = data[3]; + if(emptyCmds != 0 && !memcmp(data, "\0\0\0\0", 4)) + { + emptyCmds++; + if(emptyCmds > 32) + { + // Since there is a lot of empty space after the last Dxx command, + // we assume it's supposed to be a pattern break effect. + minVersion = ST2_00_with_Bxx; + } + } else + { + emptyCmds = 0; + } switch(eff) { @@ -880,7 +896,7 @@ } break; case 0x0B: - minVersion = Util::Max(minVersion, ST2_00_with_Bxx); + minVersion = ST2_00_with_Bxx; break; case 0x0C: case 0x0D: @@ -891,6 +907,7 @@ // Assume this is a pattern break command. minVersion = Util::Max(minVersion, ST2_00); } + emptyCmds = 1; break; case 0x0F: minVersion = Util::Max(minVersion, ST_III); @@ -910,7 +927,7 @@ for(ROWINDEX row = 0; row < 64; row++) { - ModCommand *rowBase = Patterns[pat].GetpModCommand(row, 0); + PatternRow rowBase = Patterns[pat].GetpModCommand(row, 0); for(CHANNELINDEX chn = 0; chn < 4; chn++) { ModCommand &m = rowBase[chn]; @@ -920,7 +937,7 @@ { if(m.command == 0x0D) { - if(m.param != 0 || minVersion < ST_IX) + if((m.param != 0 && minVersion != ST2_00_with_Bxx) || minVersion < ST_IX) { // Dxy is volume slide in some Soundtracker versions, D00 is a pattern break in the latest versions. m.command = 0x0A; @@ -932,6 +949,10 @@ { m.param = 0; } + } else if(m.command == 0x0C) + { + // Volume is sent as-is to the chip, which ignores the highest bit. + m.param &= 0x7F; } else if(m.command == 0x0E && (m.param > 0x01 || minVersion < ST_IX)) { // Import auto-slides as normal slides and ignore their extended behaviour. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-03-01 16:47:41
|
Revision: 1547 http://sourceforge.net/p/modplug/code/1547 Author: saga-games Date: 2013-03-01 16:47:30 +0000 (Fri, 01 Mar 2013) Log Message: ----------- [Mod] IT compression can now be configured per export format (normal IT, compat IT, MPTM) [Mod] OpenMPT: Version is now 1.21.01.17 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/soundlib/Load_it.cpp Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-03-01 16:45:36 UTC (rev 1546) +++ trunk/OpenMPT/common/version.h 2013-03-01 16:47:30 UTC (rev 1547) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 16 +#define VER_MINORMINOR 17 //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 2013-03-01 16:45:36 UTC (rev 1546) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2013-03-01 16:47:30 UTC (rev 1547) @@ -1482,7 +1482,9 @@ for (UINT nsmp=1; nsmp<=itHeader.smpnum; nsmp++) { #ifdef MODPLUG_TRACKER - bool compress = ::GetPrivateProfileInt("Misc", Samples[nsmp].GetNumChannels() > 1 ? "ITCompressionStereo" : "ITCompressionMono", 0, theApp.GetConfigFileName()) != 0; + int type = GetType() == MOD_TYPE_IT ? 1 : 4; + if(compatibilityExport) type = 2; + bool compress = (::GetPrivateProfileInt("Misc", Samples[nsmp].GetNumChannels() > 1 ? "ITCompressionStereo" : "ITCompressionMono", 0, theApp.GetConfigFileName()) & type) != 0; #else bool compress = false; #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-03-09 21:24:44
|
Revision: 1552 http://sourceforge.net/p/modplug/code/1552 Author: saga-games Date: 2013-03-09 21:24:30 +0000 (Sat, 09 Mar 2013) Log Message: ----------- [Ref] Small changes here and there (including a VS2008 compile fix) Modified Paths: -------------- trunk/OpenMPT/mptrack/CleanupSong.cpp trunk/OpenMPT/mptrack/InputHandler.cpp trunk/OpenMPT/mptrack/ModConvert.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/VstPresets.h trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/soundlib/ITCompression.cpp trunk/OpenMPT/soundlib/LOAD_DMF.CPP trunk/OpenMPT/soundlib/Load_ams.cpp trunk/OpenMPT/soundlib/Load_gdm.cpp trunk/OpenMPT/soundlib/Load_imf.cpp Modified: trunk/OpenMPT/mptrack/CleanupSong.cpp =================================================================== --- trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -530,12 +530,12 @@ // Check if any samples are not referenced in the patterns (sample mode) or by an instrument (instrument mode). // This doesn't check yet if a sample is referenced by an instrument, but actually unused in the patterns. - for(SAMPLEINDEX nSmp = pSndFile->GetNumSamples(); nSmp >= 1; nSmp--) if (pSndFile->GetSample(nSmp).pSample) + for(SAMPLEINDEX smp = 1; smp <= pSndFile->GetNumSamples(); smp--) if (pSndFile->GetSample(smp).pSample) { - if(!pSndFile->IsSampleUsed(nSmp)) + if(!pSndFile->IsSampleUsed(smp)) { - samplesUsed[nSmp] = false; - m_pModDoc->GetSampleUndo().PrepareUndo(nSmp, sundo_delete); + samplesUsed[smp] = false; + m_pModDoc->GetSampleUndo().PrepareUndo(smp, sundo_delete); } } Modified: trunk/OpenMPT/mptrack/InputHandler.cpp =================================================================== --- trunk/OpenMPT/mptrack/InputHandler.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/mptrack/InputHandler.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -146,10 +146,10 @@ /* if (keyEventType == kKeyEventUp) keyEventType=kKeyEventUp; */ - if (pSourceWnd == NULL) { + if(pSourceWnd == nullptr) pSourceWnd = m_pMainFrm; //by default, send command message to main frame. - } - if (pSourceWnd && (executeCommand != kcNull)) + + if(pSourceWnd && (executeCommand != kcNull)) { pSourceWnd->PostMessage(WM_MOD_KEYCOMMAND, executeCommand, nChar); } Modified: trunk/OpenMPT/mptrack/ModConvert.cpp =================================================================== --- trunk/OpenMPT/mptrack/ModConvert.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/mptrack/ModConvert.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -47,27 +47,27 @@ // Trim envelopes and remove release nodes. -void UpdateEnvelopes(InstrumentEnvelope *mptEnv, CSoundFile *pSndFile, std::bitset<wNumWarnings> &warnings) -//--------------------------------------------------------------------------------------------------------- +void UpdateEnvelopes(InstrumentEnvelope &mptEnv, CSoundFile &sndFile, std::bitset<wNumWarnings> &warnings) +//-------------------------------------------------------------------------------------------------------- { // shorten instrument envelope if necessary (for mod conversion) - const uint8 envMax = pSndFile->GetModSpecifications().envelopePointsMax; + const uint8 envMax = sndFile.GetModSpecifications().envelopePointsMax; - #define TRIMENV(envLen) if(envLen > envMax) { envLen = envMax; CHANGEMODTYPE_WARNING(wTrimmedEnvelopes); } +#define TRIMENV(envLen) if(envLen > envMax) { envLen = envMax; CHANGEMODTYPE_WARNING(wTrimmedEnvelopes); } - TRIMENV(mptEnv->nNodes); - TRIMENV(mptEnv->nLoopStart); - TRIMENV(mptEnv->nLoopEnd); - TRIMENV(mptEnv->nSustainStart); - TRIMENV(mptEnv->nSustainEnd); - if(mptEnv->nReleaseNode != ENV_RELEASE_NODE_UNSET) + TRIMENV(mptEnv.nNodes); + TRIMENV(mptEnv.nLoopStart); + TRIMENV(mptEnv.nLoopEnd); + TRIMENV(mptEnv.nSustainStart); + TRIMENV(mptEnv.nSustainEnd); + if(mptEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET) { - if(pSndFile->GetModSpecifications().hasReleaseNode) + if(sndFile.GetModSpecifications().hasReleaseNode) { - TRIMENV(mptEnv->nReleaseNode); + TRIMENV(mptEnv.nReleaseNode); } else { - mptEnv->nReleaseNode = ENV_RELEASE_NODE_UNSET; + mptEnv.nReleaseNode = ENV_RELEASE_NODE_UNSET; CHANGEMODTYPE_WARNING(wReleaseNode); } } @@ -516,9 +516,9 @@ for(INSTRUMENTINDEX i = 1; i <= m_SndFile.GetNumInstruments(); i++) if(m_SndFile.Instruments[i] != nullptr) { - UpdateEnvelopes(&(m_SndFile.Instruments[i]->VolEnv), &m_SndFile, warnings); - UpdateEnvelopes(&(m_SndFile.Instruments[i]->PanEnv), &m_SndFile, warnings); - UpdateEnvelopes(&(m_SndFile.Instruments[i]->PitchEnv), &m_SndFile, warnings); + UpdateEnvelopes(m_SndFile.Instruments[i]->VolEnv, m_SndFile, warnings); + UpdateEnvelopes(m_SndFile.Instruments[i]->PanEnv, m_SndFile, warnings); + UpdateEnvelopes(m_SndFile.Instruments[i]->PitchEnv, m_SndFile, warnings); } // XM requires instruments, so we create them right away. Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -2202,9 +2202,8 @@ HWND followSonghWnd; PATTERNVIEWSTATE *patternViewState; CChildFrame *pChildFrm = (CChildFrame *) GetChildFrame(); - CSoundFile *pSndFile = GetSoundFile(); - if (strcmp("CViewPattern", pChildFrm->GetCurrentViewClassName()) == 0) // dirty HACK + if(strcmp("CViewPattern", pChildFrm->GetCurrentViewClassName()) == 0) // dirty HACK { followSonghWnd = pChildFrm->GetHwndView(); PATTERNVIEWSTATE patternViewState; @@ -2213,9 +2212,9 @@ pat = patternViewState.nPattern; row = patternViewState.cursor.GetRow(); ord = patternViewState.nOrder; - } - else //patern editor object does not exist (i.e. is not active) - use saved state. + } else { + //patern editor object does not exist (i.e. is not active) - use saved state. followSonghWnd = NULL; patternViewState = pChildFrm->GetPatternViewState(); @@ -2223,26 +2222,25 @@ row = patternViewState->cursor.GetRow(); ord = patternViewState->nOrder; } - //rewbs.fix3185: if position is invalid, go to start of song. - if (ord >= m_SndFile.Order.size()) + + if(ord >= m_SndFile.Order.size()) { ord = 0; - pat = pSndFile->Order[ord]; + pat = m_SndFile.Order[ord]; } - if (pat >= m_SndFile.Patterns.Size()) + if(pat >= m_SndFile.Patterns.Size()) { pat=0; } - if (row >= pSndFile->Patterns[pat].GetNumRows()) + if(row >= m_SndFile.Patterns[pat].GetNumRows()) { row=0; } - //end rewbs.fix3185 //ensure order correlates with pattern. - if (pSndFile->Order[ord] != pat) + if(m_SndFile.Order[ord] != pat) { - ORDERINDEX tentativeOrder = pSndFile->Order.FindOrder(pat); + ORDERINDEX tentativeOrder = m_SndFile.Order.FindOrder(pat); if (tentativeOrder != ORDERINDEX_INVALID) //ensure a valid order exists. { ord = tentativeOrder; @@ -2273,8 +2271,6 @@ pChildFrm->SendViewMessage(VIEWMSG_PATTERNLOOP, loop ? 1 : 0); } - CSoundFile *pSndFile = GetSoundFile(); - ROWINDEX nRow; PATTERNINDEX nPat; ORDERINDEX nOrd; @@ -2289,28 +2285,28 @@ // Cut instruments/samples for(CHANNELINDEX i = 0; i < MAX_CHANNELS; i++) { - pSndFile->Chn[i].nPatternLoopCount = 0; - pSndFile->Chn[i].nPatternLoop = 0; - pSndFile->Chn[i].nFadeOutVol = 0; - pSndFile->Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); + m_SndFile.Chn[i].nPatternLoopCount = 0; + m_SndFile.Chn[i].nPatternLoop = 0; + m_SndFile.Chn[i].nFadeOutVol = 0; + m_SndFile.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } - if ((nOrd < m_SndFile.Order.size()) && (pSndFile->Order[nOrd] == nPat)) pSndFile->m_nCurrentOrder = pSndFile->m_nNextOrder = nOrd; - pSndFile->m_SongFlags.reset(SONG_PAUSED | SONG_STEP); + if ((nOrd < m_SndFile.Order.size()) && (m_SndFile.Order[nOrd] == nPat)) m_SndFile.m_nCurrentOrder = m_SndFile.m_nNextOrder = nOrd; + m_SndFile.m_SongFlags.reset(SONG_PAUSED | SONG_STEP); if(loop) - pSndFile->LoopPattern(nPat); + m_SndFile.LoopPattern(nPat); else - pSndFile->LoopPattern(PATTERNINDEX_INVALID); - pSndFile->m_nNextRow = 0; + m_SndFile.LoopPattern(PATTERNINDEX_INVALID); + m_SndFile.m_nNextRow = 0; // set playback timer in the status bar (and update channel status) SetElapsedTime(nOrd, 0); if(pModPlaying == this) { - pSndFile->StopAllVsti(); + m_SndFile.StopAllVsti(); } else { - pSndFile->ResumePlugins(); + m_SndFile.ResumePlugins(); } cs.Leave(); @@ -2337,8 +2333,6 @@ pChildFrm->SendViewMessage(VIEWMSG_PATTERNLOOP, 1); } - CSoundFile *pSndFile = GetSoundFile(); - ROWINDEX nRow; PATTERNINDEX nPat; ORDERINDEX nOrd; @@ -2351,24 +2345,24 @@ CriticalSection cs; // Cut instruments/samples - for(CHANNELINDEX i = pSndFile->GetNumChannels(); i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++) { - pSndFile->Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); + m_SndFile.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } - if ((nOrd < m_SndFile.Order.size()) && (pSndFile->Order[nOrd] == nPat)) pSndFile->m_nCurrentOrder = pSndFile->m_nNextOrder = nOrd; - pSndFile->m_SongFlags.reset(SONG_PAUSED | SONG_STEP); - pSndFile->LoopPattern(nPat); - pSndFile->m_nNextRow = nRow; + if ((nOrd < m_SndFile.Order.size()) && (m_SndFile.Order[nOrd] == nPat)) m_SndFile.m_nCurrentOrder = m_SndFile.m_nNextOrder = nOrd; + m_SndFile.m_SongFlags.reset(SONG_PAUSED | SONG_STEP); + m_SndFile.LoopPattern(nPat); + m_SndFile.m_nNextRow = nRow; // set playback timer in the status bar (and update channel status) SetElapsedTime(nOrd, nRow); if(pModPlaying == this) { - pSndFile->StopAllVsti(); + m_SndFile.StopAllVsti(); } else { - pSndFile->ResumePlugins(); + m_SndFile.ResumePlugins(); } cs.Leave(); @@ -2396,8 +2390,6 @@ pChildFrm->SendViewMessage(VIEWMSG_PATTERNLOOP, 0); } - CSoundFile *pSndFile = GetSoundFile(); - ROWINDEX nRow; PATTERNINDEX nPat; ORDERINDEX nOrd; @@ -2409,27 +2401,27 @@ CriticalSection cs; // Cut instruments/samples - for(CHANNELINDEX i = pSndFile->GetNumChannels(); i < MAX_CHANNELS; i++) + for(CHANNELINDEX i = m_SndFile.GetNumChannels(); i < MAX_CHANNELS; i++) { - pSndFile->Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); + m_SndFile.Chn[i].dwFlags.set(CHN_NOTEFADE | CHN_KEYOFF); } - pSndFile->m_SongFlags.reset(SONG_PAUSED | SONG_STEP); - pSndFile->SetCurrentOrder(nOrd); - if (pSndFile->Order[nOrd] == nPat) - pSndFile->DontLoopPattern(nPat, nRow); + m_SndFile.m_SongFlags.reset(SONG_PAUSED | SONG_STEP); + m_SndFile.SetCurrentOrder(nOrd); + if (m_SndFile.Order[nOrd] == nPat) + m_SndFile.DontLoopPattern(nPat, nRow); else - pSndFile->LoopPattern(nPat); - pSndFile->m_nNextRow = nRow; + m_SndFile.LoopPattern(nPat); + m_SndFile.m_nNextRow = nRow; // set playback timer in the status bar (and update channel status) SetElapsedTime(nOrd, nRow); if(pModPlaying == this) { - pSndFile->StopAllVsti(); + m_SndFile.StopAllVsti(); } else { - pSndFile->ResumePlugins(); + m_SndFile.ResumePlugins(); } cs.Leave(); @@ -2614,9 +2606,9 @@ //if macro already exists for this param, alert user and return for (int checkMacro = 0; checkMacro < NUM_MACROS; checkMacro++) { - int macroType = GetSoundFile()->m_MidiCfg.GetParameteredMacroType(checkMacro); + int macroType = m_SndFile.m_MidiCfg.GetParameteredMacroType(checkMacro); - if (macroType == sfx_plug && GetSoundFile()->m_MidiCfg.MacroToPlugParam(checkMacro) == paramToUse) + if (macroType == sfx_plug && m_SndFile.m_MidiCfg.MacroToPlugParam(checkMacro) == paramToUse) { CString message; message.Format("Parameter %02d can already be controlled with macro %X.", paramToUse, checkMacro); @@ -2626,9 +2618,9 @@ } //set new macro - if (paramToUse < 384) + if(paramToUse < 384) { - GetSoundFile()->m_MidiCfg.CreateParameteredMacro(macroToSet, sfx_plug, paramToUse); + m_SndFile.m_MidiCfg.CreateParameteredMacro(macroToSet, sfx_plug, paramToUse); } else { CString message; Modified: trunk/OpenMPT/mptrack/VstPresets.h =================================================================== --- trunk/OpenMPT/mptrack/VstPresets.h 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/mptrack/VstPresets.h 2013-03-09 21:24:30 UTC (rev 1552) @@ -44,6 +44,6 @@ #else static ErrorCode LoadFile(FileReader &, CVstPlugin &) { return invalidFile; } static bool SaveFile(std::ostream &, CVstPlugin &, bool) { return false; } - static const char *GetErrorMessage(ErrorCode) { return nullptr; } + static const char *GetErrorMessage(ErrorCode) { return "OpenMPT has been built without VST support"; } #endif // NO_VST }; Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -1682,7 +1682,7 @@ bool bank = !_strnicmp(files.first_file.substr(files.first_file.length() - 3).c_str(), "fxb", 3); std::fstream f; - f.open(files.first_file, std::ios::out | std::ios::trunc | std::ios::binary); + f.open(files.first_file.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); if(f.good() && VSTPresets::SaveFile(f, *this, bank)) { return true; Modified: trunk/OpenMPT/soundlib/ITCompression.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITCompression.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/soundlib/ITCompression.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -195,7 +195,7 @@ CopySample<int8>(sampleData, data, offset, baseLength, mptSample.GetNumChannels()); } - FileReader data(&packedData[0], packedLength + 2); + FileReader data(&packedData[0], packedLength); ModSample sample = mptSample; sample.uFlags.reset(CHN_STEREO); sample.pSample = newSampleData; Modified: trunk/OpenMPT/soundlib/LOAD_DMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/soundlib/LOAD_DMF.CPP 2013-03-09 21:24:30 UTC (rev 1552) @@ -1069,7 +1069,7 @@ } m_nType = MOD_TYPE_DMF; - m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX; // this will be converted to IT format by MPT. SONG_ITOLDEFFECTS is not set because of tremor. + m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX; // this will be converted to IT format by MPT. SONG_ITOLDEFFECTS is not set because of tremor and vibrato. SetModFlag(MSF_COMPATIBLE_PLAY, true); m_nDefaultSpeed = 6; m_nDefaultTempo = 120; Modified: trunk/OpenMPT/soundlib/Load_ams.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_ams.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/soundlib/Load_ams.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -531,11 +531,8 @@ file.Read(*this); // Read envelope points - struct - { - uint8 data[64][3]; - } env; - file.ReadStructPartial(env, numPoints * 3); + uint8 data[64][3]; + file.ReadStructPartial(data, numPoints * 3); if(numPoints <= 1) { @@ -543,8 +540,8 @@ return; } - STATIC_ASSERT(MAX_ENVPOINTS >= CountOf(env.data)); - mptEnv.nNodes = Util::Min(numPoints, uint8(CountOf(env.data))); + STATIC_ASSERT(MAX_ENVPOINTS >= CountOf(data)); + mptEnv.nNodes = Util::Min(numPoints, uint8(CountOf(data))); mptEnv.nLoopStart = loopStart; mptEnv.nLoopEnd = loopEnd; mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint; @@ -553,9 +550,9 @@ { if(i != 0) { - mptEnv.Ticks[i] = mptEnv.Ticks[i - 1] + static_cast<uint16>(Util::Max(1, env.data[i][0] | ((env.data[i][1] & 0x01) << 8))); + mptEnv.Ticks[i] = mptEnv.Ticks[i - 1] + static_cast<uint16>(Util::Max(1, data[i][0] | ((data[i][1] & 0x01) << 8))); } - mptEnv.Values[i] = env.data[i][2]; + mptEnv.Values[i] = data[i][2]; } } }; Modified: trunk/OpenMPT/soundlib/Load_gdm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_gdm.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/soundlib/Load_gdm.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -441,7 +441,6 @@ switch(m.param & 0x0F) { case 0x0: // Surround Off - m.command = CMD_S3MCMDEX; m.param = 0x90; break; case 0x1: // Surround On Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2013-03-09 14:21:31 UTC (rev 1551) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2013-03-09 21:24:30 UTC (rev 1552) @@ -30,7 +30,7 @@ { enum SongFlags { - lineSlides = 0x01, + linearSlides = 0x01, }; char title[32]; // Songname (ASCIIZ-String, max. 31 chars) @@ -46,6 +46,7 @@ uint8 unused2[8]; char im10[4]; // 'IM10' IMFChannel channels[32]; // Channel settings + uint8 orderlist[256]; // Order list (0xFF = +++; blank out anything beyond ordnum) // Convert all multi-byte numeric values to current platform's endianness or vice versa. @@ -436,7 +437,7 @@ // Song Name StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], fileHeader.title); - m_SongFlags = (fileHeader.flags & IMFFileHeader::lineSlides) ? SONG_LINEARSLIDES : SongFlags(0); + m_SongFlags = (fileHeader.flags & IMFFileHeader::linearSlides) ? SONG_LINEARSLIDES : SongFlags(0); m_nDefaultSpeed = fileHeader.tempo; m_nDefaultTempo = fileHeader.bpm; m_nDefaultGlobalVolume = Clamp(fileHeader.master, uint8(0), uint8(64)) * 4; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-03-09 21:26:40
|
Revision: 1553 http://sourceforge.net/p/modplug/code/1553 Author: saga-games Date: 2013-03-09 21:26:30 +0000 (Sat, 09 Mar 2013) Log Message: ----------- [Imp] MOD Playback: Vibrato is not applied on first tick in PT1.x mode. [Imp] M15 loader: Added support for CIA timing. [Imp] S3M loader: Added support for SAx panning (as found in PANIC.S3M) Modified Paths: -------------- trunk/OpenMPT/common/FlagSet.h trunk/OpenMPT/soundlib/Load_mod.cpp trunk/OpenMPT/soundlib/Load_s3m.cpp trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/common/FlagSet.h =================================================================== --- trunk/OpenMPT/common/FlagSet.h 2013-03-09 21:24:30 UTC (rev 1552) +++ trunk/OpenMPT/common/FlagSet.h 2013-03-09 21:26:30 UTC (rev 1553) @@ -110,6 +110,12 @@ return (flags & static_cast<store_t>(flag)) > 0; } + // Test if all specified flags are set. + bool test_all(enum_t flag) const + { + return (flags & static_cast<store_t>(flag)) == static_cast<store_t>(flag); + } + // Test if any flag is set. bool any() const { Modified: trunk/OpenMPT/soundlib/Load_mod.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_mod.cpp 2013-03-09 21:24:30 UTC (rev 1552) +++ trunk/OpenMPT/soundlib/Load_mod.cpp 2013-03-09 21:26:30 UTC (rev 1553) @@ -799,7 +799,7 @@ MODFileHeader fileHeader; file.Read(fileHeader); - // Sanity check: No more than 128 positions. We won't check the restart pos since I've encountered so many invalid values (0x6A, 0x72, 0x78, ...) that it doesn't make sense to check for them all. + // Sanity check: No more than 128 positions. if(fileHeader.numOrders > 128) { return false; @@ -828,17 +828,19 @@ m_nChannels = 4; m_nInstruments = 0; m_nDefaultSpeed = 6; - if(fileHeader.restartPos <= 0x40) + if(fileHeader.restartPos <= 0x20) { m_nDefaultTempo = 125; m_nRestartPos = (fileHeader.restartPos < fileHeader.numOrders ? fileHeader.restartPos : 0); } else { - // Sample 7 in echoing.mod won't "loop" correctly if we don't convert the tempo. + // Sample 7 in echoing.mod won't "loop" correctly if we don't convert the VBlank tempo. m_nDefaultTempo = fileHeader.restartPos * 25 / 24; m_nRestartPos = 0; if(fileHeader.restartPos != 0x78) { + // Convert to CIA timing + m_nDefaultTempo = static_cast<TEMPO>(((709378.92f / 50.0f) * 125.0f) / ((240.0f - static_cast<float>(fileHeader.restartPos)) * 122.0f)); if(minVersion > UST1_80) { // D.O.C. SoundTracker IX re-introduced the variable tempo after some other versions dropped it. Modified: trunk/OpenMPT/soundlib/Load_s3m.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_s3m.cpp 2013-03-09 21:24:30 UTC (rev 1552) +++ trunk/OpenMPT/soundlib/Load_s3m.cpp 2013-03-09 21:26:30 UTC (rev 1553) @@ -698,8 +698,12 @@ S3MConvert(m, false); } - if(m.command == CMD_MIDI) + if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xA0 && fileHeader.cwtv < S3MFileHeader::trkST3_20) { + // Convert old SAx panning to S8x (should only be found in PANIC.S3M by Purple Motion) + m.param = 0x80 | ((m.param & 0x0F) ^ 8); + } else if(m.command == CMD_MIDI) + { // PixPlay panning test if(m.param > 0x0F) { Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2013-03-09 21:24:30 UTC (rev 1552) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2013-03-09 21:26:30 UTC (rev 1553) @@ -1578,12 +1578,6 @@ UINT vibpos = chn.nVibratoPos; int vdelta = GetVibratoDelta(chn.nVibratoType, vibpos); - if((GetType() & MOD_TYPE_XM) && (chn.nVibratoType & 0x03) == 1) - { - // FT2 compatibility: Vibrato ramp down table is upside down. - // Test case: VibratoWaveforms.xm - vdelta = -vdelta; - } if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning) { @@ -1599,6 +1593,17 @@ { // Original behaviour + if(m_SongFlags.test_all(SONG_FIRSTTICK | SONG_PT1XMODE)) + { + // ProTracker doesn't apply vibrato nor advance on the first tick. + return; + } else if((GetType() & MOD_TYPE_XM) && (chn.nVibratoType & 0x03) == 1) + { + // FT2 compatibility: Vibrato ramp down table is upside down. + // Test case: VibratoWaveforms.xm + vdelta = -vdelta; + } + UINT vdepth; // IT compatibility: correct vibrato depth if(IsCompatibleMode(TRK_IMPULSETRACKER)) @@ -1653,8 +1658,8 @@ } } - // Advance vibrato position - if(m_nTickCount || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !(m_SongFlags[SONG_ITOLDEFFECTS]))) + // Advance vibrato position - IT updates on every tick, unless "old effects" are enabled (in this case it only updates on non-first ticks like other trackers) + if(!m_SongFlags[SONG_FIRSTTICK] || ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !(m_SongFlags[SONG_ITOLDEFFECTS]))) { // IT compatibility: IT has its own, more precise tables if(IsCompatibleMode(TRK_IMPULSETRACKER)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-03-09 21:27:32
|
Revision: 1554 http://sourceforge.net/p/modplug/code/1554 Author: saga-games Date: 2013-03-09 21:27:25 +0000 (Sat, 09 Mar 2013) Log Message: ----------- [Fix] New "play song from start of pattern" shortcut didn't work. [Mod] OpenMPT: Version is now 1.21.01.18 Modified Paths: -------------- trunk/OpenMPT/common/version.h trunk/OpenMPT/mptrack/CommandSet.h trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/Mainfrm.h Modified: trunk/OpenMPT/common/version.h =================================================================== --- trunk/OpenMPT/common/version.h 2013-03-09 21:26:30 UTC (rev 1553) +++ trunk/OpenMPT/common/version.h 2013-03-09 21:27:25 UTC (rev 1554) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 21 #define VER_MINOR 01 -#define VER_MINORMINOR 17 +#define VER_MINORMINOR 18 //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/CommandSet.h =================================================================== --- trunk/OpenMPT/mptrack/CommandSet.h 2013-03-09 21:26:30 UTC (rev 1553) +++ trunk/OpenMPT/mptrack/CommandSet.h 2013-03-09 21:27:25 UTC (rev 1554) @@ -86,9 +86,9 @@ kcStopSong, kcPlaySongFromStart, kcPlaySongFromCursor, + kcPlaySongFromPattern, kcPlayPatternFromStart, kcPlayPatternFromCursor, - kcPlaySongFromPattern, kcPanic, kcEstimateSongLength, kcApproxRealBPM, @@ -133,7 +133,7 @@ kcEndView=kcHelp, kcStartMisc, - kcPrevInstrument=kcStartMisc, + kcPrevInstrument=kcStartMisc, kcNextInstrument, kcPrevOctave, kcNextOctave, Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2013-03-09 21:26:30 UTC (rev 1553) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2013-03-09 21:27:25 UTC (rev 1554) @@ -1494,8 +1494,7 @@ return FALSE; } } - StopSoundFile(&m_WaveFile); - m_WaveFile.Destroy(); + StopPreview(); m_WaveFile.Create(NULL, 0); //Avoid global volume ramping when trying samples in the treeview. @@ -1572,8 +1571,7 @@ BOOL CMainFrame::PlaySoundFile(CSoundFile *pSong, UINT nInstrument, UINT nSample, UINT nNote) //------------------------------------------------------------------------------------------- { - StopSoundFile(&m_WaveFile); - m_WaveFile.Destroy(); + StopPreview(); m_WaveFile.Create(NULL, 0); m_WaveFile.m_nDefaultTempo = 125; m_WaveFile.m_nDefaultSpeed = 6; @@ -1597,7 +1595,7 @@ m_WaveFile.Patterns.Insert(1, 64); if (m_WaveFile.Patterns[0]) { - if (!nNote) nNote = 5*12+1; + if (!nNote) nNote = NOTE_MIDDLEC; ModCommand *m = m_WaveFile.Patterns[0]; m[0].note = (BYTE)nNote; m[0].instr = 1; @@ -1629,6 +1627,14 @@ } +void CMainFrame::StopPreview() +//---------------------------- +{ + StopSoundFile(&m_WaveFile); + m_WaveFile.Destroy(); +} + + BOOL CMainFrame::SetFollowSong(CModDoc *pDoc, HWND hwnd, BOOL bFollowSong, DWORD dwType) //-------------------------------------------------------------------------------------- { @@ -1982,7 +1988,7 @@ //---------------------------- { // Display Time in status bar - size_t time = 0; + CSoundFile::samplecount_t time = 0; if(m_pSndFile != nullptr && m_pSndFile->GetSampleRate() != 0) { time = m_pSndFile->GetTotalSampleCount() / m_pSndFile->GetSampleRate(); @@ -2404,10 +2410,11 @@ case kcViewGraph: //rewbs.graph case kcViewSongProperties: case kcPlayPatternFromCursor: - case kcPlayPatternFromStart: - case kcPlaySongFromCursor: - case kcPlaySongFromStart: + case kcPlayPatternFromStart: + case kcPlaySongFromCursor: + case kcPlaySongFromStart: case kcPlayPauseSong: + case kcPlaySongFromPattern: case kcStopSong: case kcEstimateSongLength: case kcApproxRealBPM: Modified: trunk/OpenMPT/mptrack/Mainfrm.h =================================================================== --- trunk/OpenMPT/mptrack/Mainfrm.h 2013-03-09 21:26:30 UTC (rev 1553) +++ trunk/OpenMPT/mptrack/Mainfrm.h 2013-03-09 21:27:25 UTC (rev 1554) @@ -402,7 +402,7 @@ // Globals static UINT m_nLastOptionsPage; - static HHOOK ghKbdHook; + static HHOOK ghKbdHook; static DWORD gdwNotificationType; // GDI @@ -446,7 +446,8 @@ CModDoc *m_pModPlaying; CSoundFile *m_pSndFile; HWND m_hFollowSong, m_hWndMidi; - DWORD m_dwStatus, m_dwTimeSec, m_dwNotifyType; + DWORD m_dwStatus, m_dwNotifyType; + CSoundFile::samplecount_t m_dwTimeSec; UINT_PTR m_nTimer; UINT m_nAvgMixChn, m_nMixChn; CHAR m_szUserText[512], m_szInfoText[512], m_szXInfoText[512]; //rewbs.xinfo @@ -458,7 +459,7 @@ public: CMainFrame(/*CString regKeyExtension*/); - VOID Initialize(); + void Initialize(); // Low-Level Audio @@ -469,7 +470,7 @@ static DWORD WINAPI AudioThread(LPVOID); static DWORD WINAPI NotifyThread(LPVOID); ULONG AudioRead(PVOID pData, ULONG cbSize); - VOID AudioDone(ULONG nBytesWritten, ULONG nLatency); + void AudioDone(ULONG nBytesWritten, ULONG nLatency); LONG audioTryOpeningDevice(UINT channels, UINT bits, UINT samplespersec); BOOL audioOpenDevice(); void audioCloseDevice(); @@ -493,7 +494,7 @@ public: static CMainFrame *GetMainFrame() { return (CMainFrame *)theApp.m_pMainWnd; } static TrackerSettings &GetSettings() { return m_Settings; } - static VOID UpdateColors(); + static void UpdateColors(); static HICON GetModIcon() { return m_hIcon; } static HFONT GetGUIFont() { return m_hGUIFont; } static HFONT GetFixedFont() { return m_hFixedFont; } @@ -514,18 +515,18 @@ // Misc functions public: - VOID SetUserText(LPCSTR lpszText); - VOID SetInfoText(LPCSTR lpszText); - VOID SetXInfoText(LPCSTR lpszText); //rewbs.xinfo - VOID SetHelpText(LPCSTR lpszText); + void SetUserText(LPCSTR lpszText); + void SetInfoText(LPCSTR lpszText); + void SetXInfoText(LPCSTR lpszText); //rewbs.xinfo + void SetHelpText(LPCSTR lpszText); UINT GetBaseOctave(); CModDoc *GetActiveDoc(); CView *GetActiveView(); //rewbs.customKeys CImageList *GetImageList() { return &m_ImageList; } PMPTCHORD GetChords() { return GetSettings().Chords; } - VOID OnDocumentCreated(CModDoc *pModDoc); - VOID OnDocumentClosed(CModDoc *pModDoc); - VOID UpdateTree(CModDoc *pModDoc, DWORD lHint=0, CObject *pHint=NULL); + void OnDocumentCreated(CModDoc *pModDoc); + void OnDocumentClosed(CModDoc *pModDoc); + void UpdateTree(CModDoc *pModDoc, DWORD lHint=0, CObject *pHint=NULL); static CInputHandler* GetInputHandler() { return m_InputHandler; } //rewbs.customKeys bool m_bModTreeHasFocus; //rewbs.customKeys CWnd *m_pNoteMapHasFocus; //rewbs.customKeys @@ -557,6 +558,7 @@ BOOL PlaySoundFile(CSoundFile *pSong, UINT nInstrument, UINT nSample, UINT nNote=0); BOOL PlayDLSInstrument(UINT nDLSBank, UINT nIns, UINT nRgn); BOOL StopSoundFile(CSoundFile *); + void StopPreview(); inline BOOL IsPlaying() const { return (m_dwStatus & MODSTATUS_PLAYING); } inline BOOL IsRendering() const { return (m_dwStatus & MODSTATUS_RENDERING); } //rewbs.VSTTimeInfo inline CModDoc *GetModPlaying() const { return (IsPlaying()||IsRendering()) ? m_pModPlaying : NULL; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-03-09 22:08:24
|
Revision: 1555 http://sourceforge.net/p/modplug/code/1555 Author: saga-games Date: 2013-03-09 22:08:15 +0000 (Sat, 09 Mar 2013) Log Message: ----------- [Fix] MOD Playback: In PT1.x mode, periods are now clamped properly (taking the finetune setting into account). Test case: AmigaLimitsFinetune.mod [Fix] Mod Cleanup: Accidentlly broke "remove unused samples" in previous refacotring commit. Modified Paths: -------------- trunk/OpenMPT/mptrack/CleanupSong.cpp trunk/OpenMPT/mptrack/Modedit.cpp trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/mptrack/CleanupSong.cpp =================================================================== --- trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-03-09 21:27:25 UTC (rev 1554) +++ trunk/OpenMPT/mptrack/CleanupSong.cpp 2013-03-09 22:08:15 UTC (rev 1555) @@ -530,7 +530,7 @@ // Check if any samples are not referenced in the patterns (sample mode) or by an instrument (instrument mode). // This doesn't check yet if a sample is referenced by an instrument, but actually unused in the patterns. - for(SAMPLEINDEX smp = 1; smp <= pSndFile->GetNumSamples(); smp--) if (pSndFile->GetSample(smp).pSample) + for(SAMPLEINDEX smp = 1; smp <= pSndFile->GetNumSamples(); smp++) if (pSndFile->GetSample(smp).pSample) { if(!pSndFile->IsSampleUsed(smp)) { Modified: trunk/OpenMPT/mptrack/Modedit.cpp =================================================================== --- trunk/OpenMPT/mptrack/Modedit.cpp 2013-03-09 21:27:25 UTC (rev 1554) +++ trunk/OpenMPT/mptrack/Modedit.cpp 2013-03-09 22:08:15 UTC (rev 1555) @@ -313,6 +313,7 @@ { m_SndFile.GetSample(i).pSample = nullptr; m_SndFile.GetSample(i).nLength = 0; + strcpy(m_SndFile.m_szNames[i], ""); } // Now, create new sample list. Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2013-03-09 21:27:25 UTC (rev 1554) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2013-03-09 22:08:15 UTC (rev 1555) @@ -1596,6 +1596,7 @@ if(m_SongFlags.test_all(SONG_FIRSTTICK | SONG_PT1XMODE)) { // ProTracker doesn't apply vibrato nor advance on the first tick. + // Test case: VibratoReset.mod return; } else if((GetType() & MOD_TYPE_XM) && (chn.nVibratoType & 0x03) == 1) { @@ -2095,12 +2096,15 @@ ProcessArpeggio(pChn, period, arpeggioSteps); - // Preserve Amiga freq limits - // Test case: AmigaLimits.s3m + // Preserve Amiga freq limits. + // In ST3, the frequency is always clamped to periods 113 to 856, while in ProTracker, + // the limit is variable, depending on the finetune of the sample. + // Test case: AmigaLimits.s3m, AmigaLimitsFinetune.mod if(m_SongFlags[SONG_AMIGALIMITS | SONG_PT1XMODE]) { - Limit(period, 113 * 4, 856 * 4); - Limit(pChn->nPeriod, 113 * 4, 856 * 4); + ASSERT(pChn->nFineTune == 0 || GetType() != MOD_TYPE_S3M); + Limit(period, 113 * 4 - pChn->nFineTune, 856 * 4 - pChn->nFineTune); + Limit(pChn->nPeriod, 113 * 4 - pChn->nFineTune, 856 * 4 - pChn->nFineTune); } ProcessPanbrello(pChn); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <sag...@us...> - 2013-03-11 14:13:32
|
Revision: 1558 http://sourceforge.net/p/modplug/code/1558 Author: saga-games Date: 2013-03-11 14:13:23 +0000 (Mon, 11 Mar 2013) Log Message: ----------- [Ref] Made VST event queue handling a bit less clumsy. Modified Paths: -------------- trunk/OpenMPT/mptrack/Vstplug.cpp trunk/OpenMPT/soundlib/plugins/PluginEventQueue.h Modified: trunk/OpenMPT/mptrack/Vstplug.cpp =================================================================== --- trunk/OpenMPT/mptrack/Vstplug.cpp 2013-03-10 15:57:47 UTC (rev 1557) +++ trunk/OpenMPT/mptrack/Vstplug.cpp 2013-03-11 14:13:23 UTC (rev 1558) @@ -2051,31 +2051,17 @@ // Add all events to the plugin's queue. for(VstInt32 i = 0; i < events->numEvents; i++) { - // Let's do some dispatching, because the VST SDK doesn't do it for us. :-( - switch(events->events[i]->type) - { - case kVstMidiType: - vstPlugin->vstEvents.Enqueue(*reinterpret_cast<VstMidiEvent *>(events->events[i])); - break; - - case kVstSysExType: - vstPlugin->vstEvents.Enqueue(*reinterpret_cast<VstMidiSysexEvent *>(events->events[i])); - break; - - default: - vstPlugin->vstEvents.Enqueue(*events->events[i]); - break; - } + vstPlugin->vstEvents.Enqueue(events->events[i]); } } } +#ifdef MODPLUG_TRACKER if(m_bRecordMIDIOut) { // Spam MIDI data to all views for(VstInt32 i = 0; i < events->numEvents; i++) { - // Let's do some dispatching, because the VST SDK doesn't do it for us. :-( if(events->events[i]->type == kVstMidiType) { VstMidiEvent *event = reinterpret_cast<VstMidiEvent *>(events->events[i]); @@ -2083,6 +2069,7 @@ } } } +#endif // MODPLUG_TRACKER } @@ -2338,7 +2325,7 @@ Log("Sending Midi %02X.%02X.%02X\n", event.midiData[0]&0xff, event.midiData[1]&0xff, event.midiData[2]&0xff); #endif - return vstEvents.Enqueue(event, insertAtFront); + return vstEvents.Enqueue(reinterpret_cast<VstEvent *>(&event), insertAtFront); } @@ -2552,15 +2539,8 @@ // Some VSTis need a note off for each instance of a note on, e.g. fabfilter. while(channel.noteOnMap[i][trackChannel]) { - if(MidiSend(MIDIEvents::NoteOff(nMidiCh, i, volume))) - { - channel.noteOnMap[i][trackChannel]--; - } else - { - // VST event queue overflow, no point in submitting more note offs. - // Note: This shouldn't happen anymore, since PluginEventQueue uses a secondary queue. - break; - } + MidiSend(MIDIEvents::NoteOff(nMidiCh, i, volume)); + channel.noteOnMap[i][trackChannel]--; } } } Modified: trunk/OpenMPT/soundlib/plugins/PluginEventQueue.h =================================================================== --- trunk/OpenMPT/soundlib/plugins/PluginEventQueue.h 2013-03-10 15:57:47 UTC (rev 1557) +++ trunk/OpenMPT/soundlib/plugins/PluginEventQueue.h 2013-03-11 14:13:23 UTC (rev 1558) @@ -85,48 +85,21 @@ // Add a VST event to the queue. Returns true on success. // Set insertFront to true to prioritise this event (i.e. add it at the front of the queue instead of the back) - bool Enqueue(const VstEvent &event, bool insertFront = false) + bool Enqueue(const VstEvent *event, bool insertFront = false) { - ASSERT(event.byteSize == sizeof(event)); -#if 1 - // True on 32-Bit hosts: No copying is necessary - static_assert(sizeof(VstEvent) == sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); - return Enqueue(reinterpret_cast<const VstMidiSysexEvent &>(event), insertFront); -#else - // True on 64-Bit hosts: VstMidiSysexEvent is bigger, so copy smaller event into bigger event. - static_assert(sizeof(VstEvent) <= sizeof(VstMidiSysexEvent), "This is no 64-Bit host!"); - VstMidiSysexEvent copyEvent; - memcpy(©Event, &event, min(event.byteSize, sizeof(event))); - return Enqueue(copyEvent, insertFront); -#endif - } + ASSERT(event->type != kVstSysExType || event->byteSize == sizeof(VstMidiSysexEvent)); + ASSERT(event->type != kVstMidiType || event->byteSize == sizeof(VstMidiEvent)); - bool Enqueue(const VstMidiEvent &event, bool insertFront = false) - { - ASSERT(event.byteSize == sizeof(event)); -#if 1 - // True on 32-Bit hosts: No copying is necessary - static_assert(sizeof(VstMidiEvent) == sizeof(VstMidiSysexEvent), "This is no 32-Bit host!"); - return Enqueue(reinterpret_cast<const VstMidiSysexEvent &>(event), insertFront); -#else - // True on 64-Bit hosts: VstMidiSysexEvent is bigger, so copy smaller event into bigger event. - static_assert(sizeof(VstMidiEvent) <= sizeof(VstMidiSysexEvent), "This is no 64-Bit host!"); - VstMidiSysexEvent copyEvent; - memcpy(©Event, &event, min(event.byteSize, sizeof(event))); - return Enqueue(copyEvent, insertFront); -#endif - } + BiggestVstEvent copyEvent; + memcpy(©Event, event, Util::Min(size_t(event->byteSize), sizeof(copyEvent))); - bool Enqueue(const VstMidiSysexEvent &event, bool insertFront = false) - { - static_assert(sizeof(BiggestVstEvent) <= sizeof(VstMidiSysexEvent), "Also check implementation here."); EnterCriticalSection(&criticalSection); if(insertFront) { - eventQueue.push_front(event); + eventQueue.push_front(copyEvent); } else { - eventQueue.push_back(event); + eventQueue.push_back(copyEvent); } LeaveCriticalSection(&criticalSection); return true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |