Skip to content
Permalink
Browse files

Add emulation of the FT2 pattern loop bug.

One of the most (in)famous FT2 bugs is the E60 bug: When E60 is used on
a pattern row x, the following pattern also starts from row x instead of
the beginning of the pattern. This can be avoided by placing a D00
pattern break on the last row of the pattern where E60 was used.

Described here: http://www.milkytracker.org/docs/MilkyTracker.html#fxE6x

Test tune:
http://api.modarchive.org/downloads.php?moduleid=55647#roadblas.xm
  • Loading branch information
eltoder committed Nov 25, 2014
1 parent 0a9280c commit afe790abc9ff106e815ec72bc64e5c95818eee4c
Showing with 19 additions and 6 deletions.
  1. +1 −1 src/libmodplug/sndfile.h
  2. +12 −3 src/snd_fx.cpp
  3. +4 −1 src/sndfile.cpp
  4. +2 −1 src/sndmix.cpp
@@ -578,7 +578,7 @@ class MODPLUG_EXPORT CSoundFile
UINT m_nType, m_nSamples, m_nInstruments;
UINT m_nTickCount, m_nTotalCount, m_nPatternDelay, m_nFrameDelay;
UINT m_nMusicSpeed, m_nMusicTempo;
UINT m_nNextRow, m_nRow;
UINT m_nNextRow, m_nRow, m_nNextStartRow;
UINT m_nPattern,m_nCurrentPattern,m_nNextPattern,m_nRestartPos;
UINT m_nMasterVolume, m_nGlobalVolume, m_nSongPreAmp;
UINT m_nFreqFactor, m_nTempoFactor, m_nOldGlbVolSlide;
@@ -21,7 +21,7 @@ DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
{
UINT dwElapsedTime=0, nRow=0, nCurrentPattern=0, nNextPattern=0, nPattern=0;
UINT nMusicSpeed=m_nDefaultSpeed, nMusicTempo=m_nDefaultTempo, nNextRow=0;
UINT nMaxRow = 0, nMaxPattern = 0;
UINT nMaxRow = 0, nMaxPattern = 0, nNextStartRow = 0;
LONG nGlbVol = m_nDefaultGlobalVolume, nOldGlbVolSlide = 0;
BYTE samples[MAX_CHANNELS];
BYTE instr[MAX_CHANNELS];
@@ -71,7 +71,8 @@ DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
if (nNextRow >= PatternSize[nPattern])
{
nNextPattern = nCurrentPattern + 1;
nNextRow = 0;
nNextRow = nNextStartRow;
nNextStartRow = 0;
}
if (!nRow)
{
@@ -106,6 +107,7 @@ DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
if (param <= nCurrentPattern) goto EndMod;
nNextPattern = param;
nNextRow = 0;
nNextStartRow = 0;
if (bAdjust)
{
pChn->nPatternLoopCount = 0;
@@ -116,6 +118,7 @@ DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
case CMD_PATTERNBREAK:
nNextRow = param;
nNextPattern = nCurrentPattern + 1;
nNextStartRow = 0;
if (bAdjust)
{
pChn->nPatternLoopCount = 0;
@@ -157,7 +160,10 @@ DWORD CSoundFile::GetLength(BOOL bAdjust, BOOL bTotal)
if ((param & 0xF0) == 0x60)
{
if (param & 0x0F) dwElapsedTime += (dwElapsedTime - patloop[nChn]) * (param & 0x0F);
else patloop[nChn] = dwElapsedTime;
else {
patloop[nChn] = dwElapsedTime;
if (m_nType & MOD_TYPE_XM) nNextStartRow = nRow;
}
}
break;
}
@@ -1169,11 +1175,13 @@ BOOL CSoundFile::ProcessEffects()
// Position Jump
case CMD_POSITIONJUMP:
nPosJump = param;
m_nNextStartRow = 0;
break;

// Pattern Break
case CMD_PATTERNBREAK:
nBreakRow = param;
m_nNextStartRow = 0;
break;

// Midi Controller
@@ -2127,6 +2135,7 @@ int CSoundFile::PatternLoop(MODCHANNEL *pChn, UINT param)
} else
{
pChn->nPatternLoop = m_nRow;
if (m_nType & MOD_TYPE_XM) m_nNextStartRow = m_nRow;
}
return -1;
}
@@ -103,6 +103,7 @@ BOOL CSoundFile::Create(LPCBYTE lpStream, DWORD dwMemLength)
m_nFrameDelay = 0;
m_nNextRow = 0;
m_nRow = 0;
m_nNextStartRow = 0;
m_nPattern = 0;
m_nCurrentPattern = 0;
m_nNextPattern = 0;
@@ -244,6 +245,7 @@ BOOL CSoundFile::Create(LPCBYTE lpStream, DWORD dwMemLength)
m_nTickCount = m_nMusicSpeed;
m_nNextRow = 0;
m_nRow = 0;
m_nNextStartRow = 0;
if ((m_nRestartPos >= MAX_ORDERS) || (Order[m_nRestartPos] >= MAX_PATTERNS)) m_nRestartPos = 0;
// Load plugins
if (gpMixPluginCreateProc)
@@ -678,6 +680,7 @@ void CSoundFile::SetCurrentPos(UINT nPos)
}
m_nNextPattern = nPattern;
m_nNextRow = nRow;
m_nNextStartRow = 0;
m_nTickCount = m_nMusicSpeed;
m_nBufferCount = 0;
m_nPatternDelay = 0;
@@ -706,7 +709,7 @@ void CSoundFile::SetCurrentOrder(UINT nPos)
} else
{
m_nNextPattern = nPos;
m_nRow = m_nNextRow = 0;
m_nRow = m_nNextRow = m_nNextStartRow = 0;
m_nPattern = 0;
m_nTickCount = m_nMusicSpeed;
m_nBufferCount = 0;
@@ -419,7 +419,8 @@ BOOL CSoundFile::ProcessRow()
if (m_nNextRow >= PatternSize[m_nPattern])
{
if (!(m_dwSongFlags & SONG_PATTERNLOOP)) m_nNextPattern = m_nCurrentPattern + 1;
m_nNextRow = 0;
m_nNextRow = m_nNextStartRow;
m_nNextStartRow = 0;
}
// Reset channel values
MODCHANNEL *pChn = Chn;

0 comments on commit afe790a

Please sign in to comment.
You can’t perform that action at this time.