Skip to content

Commit

Permalink
Add emulation of the FT2 pattern loop bug.
Browse files Browse the repository at this point in the history
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 27, 2014
1 parent 0a9280c commit afe790a
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/libmodplug/sndfile.h
Expand Up @@ -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;
Expand Down
15 changes: 12 additions & 3 deletions src/snd_fx.cpp
Expand Up @@ -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];
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
5 changes: 4 additions & 1 deletion src/sndfile.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/sndmix.cpp
Expand Up @@ -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;
Expand Down

0 comments on commit afe790a

Please sign in to comment.