From: <sag...@us...> - 2014-09-27 15:49:44
|
Revision: 4312 http://sourceforge.net/p/modplug/code/4312 Author: saga-games Date: 2014-09-27 15:49:35 +0000 (Sat, 27 Sep 2014) Log Message: ----------- [Imp] Song length estimation: Slightly improve calculation of nested pattern loops (http://bugs.openmpt.org/view.php?id=591) Modified Paths: -------------- trunk/OpenMPT/common/misc_util.h trunk/OpenMPT/soundlib/Snd_fx.cpp Modified: trunk/OpenMPT/common/misc_util.h =================================================================== --- trunk/OpenMPT/common/misc_util.h 2014-09-26 09:06:17 UTC (rev 4311) +++ trunk/OpenMPT/common/misc_util.h 2014-09-27 15:49:35 UTC (rev 4312) @@ -296,27 +296,6 @@ } -// Greatest Common Divisor. -template <class T> -T gcd(T a, T b) -//------------- -{ - if(a < 0) - a = -a; - if(b < 0) - b = -b; - do - { - if(a == 0) - return b; - b %= a; - if(b == 0) - return a; - a %= b; - } while(true); -} - - // Returns sign of a number (-1 for negative numbers, 1 for positive numbers, 0 for 0) template <class T> int sgn(T value) @@ -467,6 +446,38 @@ return (a >= 0) ? mpt::saturate_cast<int32>(a / c) : mpt::saturate_cast<int32>((a - (c - 1)) / c); } + // Greatest Common Divisor. Always returns non-negative number. + template <class T> + T gcd(T a, T b) + { + if(a < 0) + a = -a; + if(b < 0) + b = -b; + do + { + if(a == 0) + return b; + b %= a; + if(b == 0) + return a; + a %= b; + } while(true); + } + + // Least Common Multiple. Always returns non-negative number. + template <class T> + int lcm(T a, T b) + { + if(a < 0) + a = -a; + if(b < 0) + b = -b; + if((a | b) == 0) + return 0; + return a / gcd<T>(a, b) * b; + } + template<typename T, std::size_t n> class fixed_size_queue { Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-09-26 09:06:17 UTC (rev 4311) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2014-09-27 15:49:35 UTC (rev 4312) @@ -775,14 +775,24 @@ if(patternLoopEndedOnThisRow) { p = Patterns[nPattern].GetRow(nRow); + std::map<double, int> startTimes; + // This is really just a simple estimation for nested pattern loops. It should handle cases correctly where all parallel loops start and end on the same row. + // If one of them starts or ends "in between", it will most likely calculate a wrong duration. + // For S3M files, it's also way off. for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); p++, nChn++) { if((p->command == CMD_S3MCMDEX && p->param >= 0xB1 && p->param <= 0xBF) || (p->command == CMD_MODCMDEX && p->param >= 0x61 && p->param <= 0x6F)) { - memory.elapsedTime += (memory.elapsedTime - memory.chnSettings[nChn].patLoop) * (double)(p->param & 0x0F); + const double start = memory.chnSettings[nChn].patLoop; + if(!startTimes[start]) startTimes[start] = 1; + startTimes[start] = Util::lcm<int>(startTimes[start], 1 + (p->param & 0x0F)); } } + for(std::map<double, int>::iterator i = startTimes.begin(); i != startTimes.end(); i++) + { + memory.elapsedTime += (memory.elapsedTime - i->first) * (double)(i->second - 1); + } if(GetType() == MOD_TYPE_IT) { // IT pattern loop start row update - at the end of a pattern loop, set pattern loop start to next row (for upcoming pattern loops with missing SB0) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |