From: <sag...@us...> - 2011-02-11 23:29:06
|
Revision: 797 http://modplug.svn.sourceforge.net/modplug/?rev=797&view=rev Author: saga-games Date: 2011-02-11 23:28:58 +0000 (Fri, 11 Feb 2011) Log Message: ----------- [Mod] The visited rows mechanism is now used everywhere, not only for song length detection. This introduces some great changes in the code. One advantage of the new mechanism is that backwards playing patterns can now be exported to WAV properly (hehe). The new code might break the "loop song" feature sometimes, let's see how that works... [Ref] Some changes to GetLength()'s return values and other stuff related to the modification above. [Mod] OpenMPT: Version is now 1.19.00.23 Modified Paths: -------------- trunk/OpenMPT/mptrack/Ctrl_seq.cpp trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/View_pat.cpp trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/Snd_fx.cpp trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/mptrack/Ctrl_seq.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/mptrack/Ctrl_seq.cpp 2011-02-11 23:28:58 UTC (rev 797) @@ -303,24 +303,26 @@ if ((bIsPlaying) && (pSndFile->m_dwSongFlags & SONG_PATTERNLOOP)) { BEGIN_CRITICAL(); + // update channel parameters and play time + m_pModDoc->SetElapsedTime(m_nScrollPos, 0); + pSndFile->m_nPattern = n; pSndFile->m_nCurrentPattern = pSndFile->m_nNextPattern = m_nScrollPos; pMainFrm->ResetNotificationBuffer(); //rewbs.toCheck pSndFile->m_nNextRow = 0; END_CRITICAL(); - } else - if (m_pParent->GetFollowSong()) + } else if (m_pParent->GetFollowSong()) { BEGIN_CRITICAL(); DWORD dwPaused = pSndFile->m_dwSongFlags & (SONG_PAUSED|SONG_STEP|SONG_PATTERNLOOP); + + //if (!(dwPaused & SONG_PATTERNLOOP)) // why? + // update channel parameters and play time + m_pModDoc->SetElapsedTime(m_nScrollPos, 0); + pSndFile->m_nCurrentPattern = m_nScrollPos; pSndFile->SetCurrentOrder(m_nScrollPos); pSndFile->m_dwSongFlags |= dwPaused; - //if (!(dwPaused & SONG_PATTERNLOOP)) // why? - { - // update channel parameters and play time - m_pModDoc->SetElapsedTime(m_nScrollPos, 0); - } if (bIsPlaying) pMainFrm->ResetNotificationBuffer(); END_CRITICAL(); } Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2011-02-11 23:28:58 UTC (rev 797) @@ -690,6 +690,8 @@ DWORD dwOrds = m_pSndFile->Order.GetLengthFirstEmpty(); if ((m_nMaxPatterns < dwOrds) && (dwOrds > 0)) l = (l*m_nMaxPatterns) / dwOrds; } + m_pSndFile->InitializeVisitedRows(true); + if (l < max) max = l; if (progress != NULL) @@ -1048,6 +1050,7 @@ CSoundFile::InitPlayer(TRUE); CSoundFile::gdwSoundSetup |= SNDMIX_DIRECTTODISK; if ((!m_dwFileLimit) && (!m_dwSongLimit)) CSoundFile::gdwSoundSetup |= SNDMIX_NOBACKWARDJUMPS; + m_pSndFile->InitializeVisitedRows(true); // Setting up file limits and progress range if ((!m_dwFileLimit) || (m_dwFileLimit > 512000)) m_dwFileLimit = 512000; m_dwFileLimit <<= 10; @@ -1138,6 +1141,7 @@ CSoundFile::gdwSoundSetup &= ~(SNDMIX_DIRECTTODISK|SNDMIX_NOBACKWARDJUMPS); m_pSndFile->SetRepeatCount(oldrepeat); m_pSndFile->m_nMaxOrderPosition = 0; + m_pSndFile->InitializeVisitedRows(true); CMainFrame::UpdateAudioParameters(TRUE); // Success if (bSaveWave) Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2011-02-11 23:28:58 UTC (rev 797) @@ -1923,6 +1923,7 @@ //m_SndFile.m_dwSongFlags &= ~SONG_STEP; m_SndFile.m_dwSongFlags &= ~(SONG_STEP|SONG_PATTERNLOOP); m_SndFile.SetCurrentPos(0); + m_SndFile.InitializeVisitedRows(true); pMainFrm->ResetElapsedTime(); BEGIN_CRITICAL(); m_SndFile.ResumePlugins(); @@ -3692,7 +3693,7 @@ if(pMainFrm == NULL) return; - const double dPatternPlaytime = m_SndFile.GetPlaybackTimeAt(nOrd, nRow, false); + const double dPatternPlaytime = m_SndFile.GetPlaybackTimeAt(nOrd, nRow, true); pMainFrm->SetElapsedTime((DWORD) (max(0, dPatternPlaytime) * 1000)); } Modified: trunk/OpenMPT/mptrack/View_pat.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_pat.cpp 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/mptrack/View_pat.cpp 2011-02-11 23:28:58 UTC (rev 797) @@ -5453,7 +5453,7 @@ ORDERINDEX currentOrder = SendCtrlMessage(CTRLMSG_GETCURRENTORDER); if(pSndFile->Order[currentOrder] == m_nPattern) { - const double t = pSndFile->GetPlaybackTimeAt(currentOrder, m_nRow, true); + const double t = pSndFile->GetPlaybackTimeAt(currentOrder, m_nRow, false); if(t < 0) msg.Format("Unable to determine the time. Possible cause: No order %d, row %d found from play sequence", currentOrder, m_nRow); else Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/mptrack/version.h 2011-02-11 23:28:58 UTC (rev 797) @@ -15,7 +15,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 19 #define VER_MINOR 00 -#define VER_MINORMINOR 22 +#define VER_MINORMINOR 23 //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/Snd_fx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_fx.cpp 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2011-02-11 23:28:58 UTC (rev 797) @@ -73,23 +73,24 @@ } */ -double CSoundFile::GetLength(bool bAdjust, ORDERINDEX endOrder, ROWINDEX endRow) -//------------------------------------------------------------------------------ -{ - bool dummy = false; - double result = GetLength(dummy, bAdjust, endOrder, endRow); - return result; -} - // Get mod length in various cases. Parameters: -// &targetReached: Will be set to true if the specified order/row combination has been reached while going through the module. -// bAdjust: If enabled, the mod parameters (such as global volume, speed, tempo, etc...) will be memorized (if the target has been reached) when leaving the function (i.e. they won't be reset to the previous values) -// endOrder: Order which should be reached (ORDERINDEX_INVALID means whole song) -// endRow: Row in that order that should be reached -double CSoundFile::GetLength(bool& targetReached, bool bAdjust, ORDERINDEX endOrder, ROWINDEX endRow) -//--------------------------------------------------------------------------------------------------- +// [in] bAdjust: If enabled, the mod parameters (such as global volume, speed, tempo, etc...) will be memorized (if the target has been reached) when leaving the function (i.e. they won't be reset to the previous values) +// [in] endOrder: Order which should be reached (ORDERINDEX_INVALID means whole song) +// [in] endRow: Row in that order that should be reached +// [out] duration: total time in seconds +// [out] targetReached: true if the specified order/row combination has been reached while going through the module. +// [out] endOrder: last parsed order (if no target is specified, this is the first order that is parsed twice, i.e. not the *last* played order) +// [out] endRow: last parsed row (dito) +GetLengthType CSoundFile::GetLength(bool bAdjust, ORDERINDEX endOrder, ROWINDEX endRow) +//------------------------------------------------------------------------------------- { + GetLengthType retval; + retval.duration = 0.0; + retval.targetReached = false; + retval.endOrder = ORDERINDEX_INVALID; + retval.endRow = ROWINDEX_INVALID; + // -> CODE#0022 // -> DESC="alternative BPM/Speed interpretation method" // UINT dwElapsedTime=0, nRow=0, nCurrentPattern=0, nNextPattern=0, nPattern=Order[0]; @@ -166,7 +167,7 @@ //Check whether target reached. if(nCurrentPattern == endOrder && nRow == endRow) { - targetReached = true; + retval.targetReached = true; break; } @@ -420,10 +421,17 @@ } } + if(retval.targetReached || endOrder == ORDERINDEX_INVALID || endRow == ROWINDEX_INVALID) + { + retval.endOrder = nCurrentPattern; + retval.endRow = nRow; + } + retval.duration = dElapsedTime / 1000.0; + // Store final variables if (bAdjust) { - if (targetReached || endOrder == ORDERINDEX_INVALID || endRow == ROWINDEX_INVALID) + if (retval.targetReached || endOrder == ORDERINDEX_INVALID || endRow == ROWINDEX_INVALID) { // Target found, or there is no target (i.e. play whole song)... m_nGlobalVolume = nGlbVol; @@ -438,7 +446,7 @@ if (vols[n] != 0xFF) { if (vols[n] > 64) vols[n] = 64; - Chn[n].nVolume = vols[n] << 2; + Chn[n].nVolume = vols[n] * 4; } } } else @@ -449,10 +457,10 @@ m_nGlobalVolume = m_nDefaultGlobalVolume; } // When adjusting the playback status, we will also want to update the visited rows vector according to the current position. - m_bVisitedRows = visitedRows; + m_VisitedRows = visitedRows; } - return dElapsedTime / 1000.0; + return retval; } @@ -1194,7 +1202,7 @@ //rewbs: Copy mute and FX status from master chan. //I'd like to copy other flags too, but this would change playback behaviour. - p->dwFlags |= (pChn->dwFlags & CHN_MUTE) | (pChn->dwFlags & CHN_NOFX); + p->dwFlags |= (pChn->dwFlags & (CHN_MUTE|CHN_NOFX)); p->nMasterChn = nChn+1; p->nCommand = 0; @@ -1241,7 +1249,8 @@ //------------------------------- { MODCHANNEL *pChn = Chn; - int nBreakRow = -1, nPosJump = -1, nPatLoopRow = -1; + ROWINDEX nBreakRow = ROWINDEX_INVALID, nPatLoopRow = ROWINDEX_INVALID; + ORDERINDEX nPosJump = ORDERINDEX_INVALID; // -> CODE#0010 // -> DESC="add extended parameter mechanism to pattern effects" @@ -2088,45 +2097,28 @@ if(m_dwSongFlags & SONG_FIRSTTICK) { // Pattern Loop - if (nPatLoopRow >= 0) + if (nPatLoopRow != ROWINDEX_INVALID) { m_nNextPattern = m_nCurrentPattern; m_nNextRow = nPatLoopRow; if (m_nPatternDelay) m_nNextRow++; + // As long as the pattern loop is running, mark the looped rows as not visited yet + for(ROWINDEX nRow = nPatLoopRow; nRow <= m_nRow; nRow++) + { + SetRowVisited(m_nCurrentPattern, nRow, false); + } } else // Pattern Break / Position Jump only if no loop running - if ((nBreakRow >= 0) || (nPosJump >= 0)) + if ((nBreakRow != ROWINDEX_INVALID) || (nPosJump != ORDERINDEX_INVALID)) { - bool bNoLoop = false; - if (nPosJump < 0) nPosJump = m_nCurrentPattern+1; - if (nBreakRow < 0) nBreakRow = 0; + if (nPosJump == ORDERINDEX_INVALID) nPosJump = m_nCurrentPattern + 1; + if (nBreakRow == ROWINDEX_INVALID) nBreakRow = 0; + m_dwSongFlags |= SONG_BREAKTOROW; - if(nBreakRow >= 0) m_dwSongFlags |= SONG_BREAKTOROW; - // ModPlug Tracker & ModPlugin allow backward jumps - #ifndef FASTSOUNDLIB - if ((nPosJump < (int)m_nCurrentPattern) - || ((nPosJump == (int)m_nCurrentPattern) && (nBreakRow <= (int)m_nRow))) + if (nPosJump >= Order.size()) { - if (!IsValidBackwardJump(m_nCurrentPattern, m_nRow, nPosJump, nBreakRow)) - { - if (m_nRepeatCount) - { - if (m_nRepeatCount > 0) m_nRepeatCount--; - } else - { - #ifdef MODPLUG_TRACKER - if (gdwSoundSetup & SNDMIX_NOBACKWARDJUMPS) - #endif - // Backward jump disabled - bNoLoop = true; - } - } - } - #endif // FASTSOUNDLIB - //rewbs.fix - //if (((!bNoLoop) && (nPosJump < MAX_ORDERS)) - if (nPosJump>=Order.size()) nPosJump = 0; + } // This checks whether we're jumping to the same row we're already on. // Sounds pretty stupid and pointless to me. And noone else does this, either. @@ -2145,6 +2137,7 @@ m_bPatternTransitionOccurred = true; } } //Ends condition (nBreakRow >= 0) || (nPosJump >= 0) + //SetRowVisited(m_nCurrentPattern, m_nRow); } return TRUE; } @@ -3864,6 +3857,7 @@ } +// This is how backward jumps should not be tested. :) (now unused) BOOL CSoundFile::IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const //---------------------------------------------------------------------------------------------------------- { @@ -4236,7 +4230,7 @@ { if(pRowVector == nullptr) { - pRowVector = &m_bVisitedRows; + pRowVector = &m_VisitedRows; } pRowVector->resize(Order.GetLengthTailTrimmed()); @@ -4268,7 +4262,7 @@ if(pRowVector == nullptr) { - pRowVector = &m_bVisitedRows; + pRowVector = &m_VisitedRows; } // The module might have been edited in the meantime - so we have to extend this a bit. @@ -4296,7 +4290,7 @@ if(pRowVector == nullptr) { - pRowVector = &m_bVisitedRows; + pRowVector = &m_VisitedRows; } // The row slot for this row has not been assigned yet - Just return false, as this means that the program has not played the row yet. Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2011-02-11 23:28:58 UTC (rev 797) @@ -755,6 +755,8 @@ m_nNextRow = 0; m_nRow = 0; + InitializeVisitedRows(true); + switch(m_nTempoMode) { case tempo_mode_alternative: @@ -1212,7 +1214,7 @@ //rewbs.VSTCompliance void CSoundFile::SuspendPlugins() -//------------------------------ +//------------------------------- { for (UINT iPlug=0; iPlug<MAX_MIXPLUGINS; iPlug++) { @@ -1269,7 +1271,7 @@ void CSoundFile::RecalculateGainForAllPlugs() -//------------------------------------------ +//------------------------------------------- { for (UINT iPlug=0; iPlug<MAX_MIXPLUGINS; iPlug++) { @@ -1337,7 +1339,7 @@ } ORDERINDEX CSoundFile::FindOrder(PATTERNINDEX nPat, UINT startFromOrder, bool direction) -//------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------- { ORDERINDEX foundAtOrder = ORDERINDEX_INVALID; ORDERINDEX candidateOrder = 0; @@ -1626,7 +1628,7 @@ } bool CSoundFile::MoveChannel(UINT chnFrom, UINT chnTo) -//----------------------------------------------------- +//---------------------------------------------------- { //Implementation of move channel using ReArrangeChannels(...). So this function //only creates correct newOrder-vector used in the ReArrangeChannels(...). @@ -1734,7 +1736,7 @@ #ifndef MODPLUG_NO_FILESAVE UINT CSoundFile::WriteSample(FILE *f, MODSAMPLE *pSmp, UINT nFlags, UINT nMaxLen) -//----------------------------------------------------------------------------------- +//------------------------------------------------------------------------------- { UINT len = 0, bufcount; char buffer[4096]; @@ -1949,7 +1951,7 @@ // 6 = unsigned 16-bit PCM data UINT CSoundFile::ReadSample(MODSAMPLE *pSmp, UINT nFlags, LPCSTR lpMemFile, DWORD dwMemLength, const WORD format) -//----------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------- { if ((!pSmp) || (pSmp->nLength < 2) || (!lpMemFile)) return 0; @@ -2429,7 +2431,7 @@ void CSoundFile::AdjustSampleLoop(MODSAMPLE *pSmp) -//---------------------------------------------------- +//------------------------------------------------ { if ((!pSmp->pSample) || (!pSmp->nLength)) return; if (pSmp->nLoopEnd > pSmp->nLength) pSmp->nLoopEnd = pSmp->nLength; @@ -2578,7 +2580,7 @@ void CSoundFile::FrequencyToTranspose(MODSAMPLE *psmp) -//-------------------------------------------------------- +//---------------------------------------------------- { int f2t = FrequencyToTranspose(psmp->nC5Speed); int transp = f2t >> 7; @@ -2814,14 +2816,14 @@ if (!from || from >= MAX_SAMPLES || !to || to >= MAX_SAMPLES) return false; if (/*!Ins[from].pSample ||*/ Samples[to].pSample) return true; - MODSAMPLE *pinsf = &Samples[from]; - MODSAMPLE *pinst = &Samples[to]; + MODSAMPLE *pFrom = &Samples[from]; + MODSAMPLE *pTo = &Samples[to]; - memcpy(pinst, pinsf, sizeof(MODSAMPLE)); + memcpy(pTo, pFrom, sizeof(MODSAMPLE)); - pinsf->pSample = nullptr; - pinsf->nLength = 0; - pinsf->uFlags &= ~(CHN_16BIT); + pFrom->pSample = nullptr; + pFrom->nLength = 0; + pFrom->uFlags &= ~(CHN_16BIT); return true; } @@ -2847,7 +2849,7 @@ { // m_defaultInstrument is currently only used to get default values for extented properties. // In the future we can make better use of this. - memset(&m_defaultInstrument, 0, sizeof(MODINSTRUMENT)); + MemsetZero(m_defaultInstrument); m_defaultInstrument.nResampling = SRCMODE_DEFAULT; m_defaultInstrument.nFilterMode = FLTMODE_UNCHANGED; m_defaultInstrument.nPPC = 5*12; @@ -2889,7 +2891,7 @@ } bool CSoundFile::LoadStaticTunings() -//----------------------------------- +//---------------------------------- { if(s_pTuningsSharedLocal || s_pTuningsSharedBuiltIn) return true; //For now not allowing to reload tunings(one should be careful when reloading them @@ -2941,8 +2943,8 @@ -void CSoundFile::SetDefaultInstrumentValues(MODINSTRUMENT *pIns) -//----------------------------------------------------------------- +void CSoundFile::SetDefaultInstrumentValues(MODINSTRUMENT *pIns) +//-------------------------------------------------------------- { pIns->nResampling = m_defaultInstrument.nResampling; pIns->nFilterMode = m_defaultInstrument.nFilterMode; @@ -2957,7 +2959,7 @@ long CSoundFile::GetSampleOffset() -//------------------------------- +//-------------------------------- { //TODO: This is where we could inform patterns of the exact song position when playback starts. //order: m_nNextPattern @@ -2967,7 +2969,7 @@ } string CSoundFile::GetNoteName(const CTuning::NOTEINDEXTYPE& note, const INSTRUMENTINDEX inst) const -//---------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- { if((inst >= MAX_INSTRUMENTS && inst != INSTRUMENTINDEX_INVALID) || note < 1 || note > NOTE_MAX) return "BUG"; @@ -3054,12 +3056,11 @@ } -double CSoundFile::GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool resetVars) -//-------------------------------------------------------------------------------- +double CSoundFile::GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVars) +//--------------------------------------------------------------------------------- { - bool targetReached = false; - const double t = GetLength(targetReached, !resetVars, ord, row); - if(targetReached) return t; + const GetLengthType t = GetLength(updateVars, ord, row); + if(t.targetReached) return t.duration; else return -1; //Given position not found from play sequence. } Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/soundlib/Sndfile.h 2011-02-11 23:28:58 UTC (rev 797) @@ -487,6 +487,16 @@ typedef vector<VisitedRowsBaseType> VisitedRowsType; +// Return values for GetLength() +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 + ORDERINDEX endOrder; // 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 endRow; // last parsed row (dito) +}; + + //Note: These are bit indeces. MSF <-> Mod(Specific)Flag. //If changing these, ChangeModTypeTo() might need modification. const BYTE MSF_COMPATIBLE_PLAY = 0; //IT/MPT/XM @@ -508,8 +518,8 @@ void ChangeModTypeTo(const MODTYPE& newType); // Returns value in seconds. If given position won't be played at all, returns -1. - // If resetVars is true, the state of various playback variables will be retained. - double GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool resetVars); + // If updateVars is true, the state of various playback variables will be updated according to the playback position. + double GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVars); uint16 GetModFlags() const {return m_ModFlags;} void SetModFlags(const uint16 v) {m_ModFlags = v;} @@ -566,7 +576,7 @@ const CModSpecifications* m_pModSpecs; // For handling backwards jumps and stuff to prevent infinite loops when counting the mod length or rendering to wav. - VisitedRowsType m_bVisitedRows; + VisitedRowsType m_VisitedRows; @@ -693,15 +703,13 @@ UINT GetMusicSpeed() const { return m_nMusicSpeed; } UINT GetMusicTempo() const { return m_nMusicTempo; } - double GetLength(bool bAdjust, ORDERINDEX ord = ORDERINDEX_MAX, ROWINDEX row = ROWINDEX_MAX); -private: //Get modlength in various cases: total length, length to //specific order&row etc. Return value is in seconds. - double GetLength(bool& targetReached, bool bAdjust, ORDERINDEX ord, ROWINDEX row); + GetLengthType GetLength(bool bAdjust, ORDERINDEX ord = ORDERINDEX_INVALID, ROWINDEX row = ROWINDEX_INVALID); public: //Returns song length in seconds. - DWORD GetSongTime() { return static_cast<DWORD>((m_nTempoMode == tempo_mode_alternative) ? GetLength(false) + 1.0 : GetLength(false) + 0.5); } + DWORD GetSongTime() { return static_cast<DWORD>((m_nTempoMode == tempo_mode_alternative) ? GetLength(false).duration + 1.0 : GetLength(false).duration + 0.5); } // A repeat count value of -1 means infinite loop void SetRepeatCount(int n) { m_nRepeatCount = n; } @@ -901,6 +909,7 @@ BOOL IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const; void UpdateTimeSignature(); + UINT GetNumTicksOnCurrentRow() { return m_nMusicSpeed * (m_nPatternDelay + 1) + m_nFrameDelay; }; public: // Write pattern effect functions bool TryWriteEffect(PATTERNINDEX nPat, ROWINDEX nRow, BYTE nEffect, BYTE nParam, bool bIsVolumeEffect, CHANNELINDEX nChn = CHANNELINDEX_INVALID, bool bAllowMultipleEffects = true, bool bAllowNextRow = false, bool bRetry = true); Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2011-02-11 22:45:26 UTC (rev 796) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2011-02-11 23:28:58 UTC (rev 797) @@ -657,7 +657,7 @@ if ((m_nPattern == Order.GetInvalidPatIndex()) || (m_nCurrentPattern >= Order.size())) { - if (!m_nRepeatCount) return FALSE; + //if (!m_nRepeatCount) return FALSE; ORDERINDEX nRestartPosOverride = m_nRestartPos; if(!m_nRestartPos && m_nCurrentPattern <= Order.size() && m_nCurrentPattern > 0) @@ -734,9 +734,10 @@ } //Check for end of song or bad pattern if (m_nCurrentPattern >= Order.size() - || - (Order[m_nCurrentPattern] >= Patterns.Size()) - || (!Patterns[Order[m_nCurrentPattern]]) ) { + || (Order[m_nCurrentPattern] >= Patterns.Size()) + || (!Patterns[Order[m_nCurrentPattern]]) ) + { + InitializeVisitedRows(true); return FALSE; } @@ -761,9 +762,42 @@ } // Weird stuff? - if ((m_nPattern >= Patterns.Size()) || (!Patterns[m_nPattern])) return FALSE; + if (!Patterns.IsValidPat(m_nPattern)) return FALSE; // Should never happen if (m_nRow >= Patterns[m_nPattern].GetNumRows()) m_nRow = 0; + + // Has this row been visited before? We might want to stop playback now. + // But: We will not mark the row as modified if the song is not in loop mode but + // the pattern loop (editor flag, not to be confused with the pattern loop effect) + // flag is set - because in that case, the module would stop after the first pattern loop... + const bool overrideLoopCheck = (m_nRepeatCount != -1) && (m_dwSongFlags & SONG_PATTERNLOOP); + if(!overrideLoopCheck && IsRowVisited(m_nCurrentPattern, m_nRow, true)) + { + InitializeVisitedRows(true); + if(m_nRepeatCount) + { + // repeat count == -1 means repeat infinitely. + if (m_nRepeatCount > 0) + { + m_nRepeatCount--; + } + // We shouldn't forget that we actually just visited this row (InitializeVisitedRows cleared it). + SetRowVisited(m_nCurrentPattern, m_nRow); + } else + { +#ifdef MODPLUG_TRACKER + // Let's check again if this really is the end of the song. + // The visited rows vector might have been screwed up while editing... + GetLengthType t = GetLength(false); + if(t.endOrder == m_nCurrentPattern && t.endRow == m_nRow) +#endif // MODPLUG_TRACKER + { + // This is really the song's end! + return FALSE; + } + } + } + m_nNextRow = m_nRow + 1; if (m_nNextRow >= Patterns[m_nPattern].GetNumRows()) { @@ -1611,7 +1645,6 @@ if ((pChn->nAutoVibDepth >> 8) > pSmp->nVibDepth) pChn->nAutoVibDepth = pSmp->nVibDepth << 8; } - const int vibpos = pChn->nAutoVibPos & 0xFF; pChn->nAutoVibPos += pSmp->nVibRate; int vdelta; switch(pSmp->nVibType) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |