|
From: <sag...@us...> - 2013-02-22 22:55:24
|
Revision: 1545
http://sourceforge.net/p/modplug/code/1545
Author: saga-games
Date: 2013-02-22 22:55:15 +0000 (Fri, 22 Feb 2013)
Log Message:
-----------
[Fix] IT Compatibility: There is no unified effect memory between the volume column effects, and the volume slide commands there also don't share their effect memory with the effect column slides (test case: VolColMemory.it)
Modified Paths:
--------------
trunk/OpenMPT/soundlib/ModChannel.h
trunk/OpenMPT/soundlib/Snd_fx.cpp
trunk/OpenMPT/soundlib/Sndfile.h
trunk/OpenMPT/soundlib/modcommand.h
Modified: trunk/OpenMPT/soundlib/ModChannel.h
===================================================================
--- trunk/OpenMPT/soundlib/ModChannel.h 2013-02-21 15:24:54 UTC (rev 1544)
+++ trunk/OpenMPT/soundlib/ModChannel.h 2013-02-22 22:55:15 UTC (rev 1545)
@@ -84,7 +84,7 @@
uint8 nNewNote, nNewIns, nCommand, nArpeggio;
uint8 nOldVolumeSlide, nOldFineVolUpDown;
uint8 nOldPortaUpDown, nOldFinePortaUpDown, nOldExtraFinePortaUpDown;
- uint8 nOldPanSlide, nOldChnVolSlide;
+ uint8 nOldPanSlide, nOldChnVolSlide, nOldVolColSlide;
uint8 nVibratoType, nVibratoSpeed, nVibratoDepth;
uint8 nTremoloType, nTremoloSpeed, nTremoloDepth;
uint8 nPanbrelloType, nPanbrelloSpeed, nPanbrelloDepth;
@@ -140,7 +140,6 @@
resetSetPosAdvanced = 4, // Reset more runtime channel attributes
resetSetPosFull = resetSetPosBasic | resetSetPosAdvanced | resetChannelSettings, // Reset all runtime channel attributes
resetTotal = resetSetPosFull,
-
};
void Reset(ResetFlags resetMask, const CSoundFile &sndFile, CHANNELINDEX sourceChannel);
Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Snd_fx.cpp 2013-02-21 15:24:54 UTC (rev 1544)
+++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2013-02-22 22:55:15 UTC (rev 1545)
@@ -795,6 +795,9 @@
reset = (!pChn->nLength
|| (insNumber && bPorta && m_SongFlags[SONG_ITCOMPATGXX])
|| (insNumber && !bPorta && pChn->dwFlags[CHN_NOTEFADE | CHN_KEYOFF] && m_SongFlags[SONG_ITOLDEFFECTS]));
+ // NOTE: IT2.14 with SB/GUS/etc. output is different. We are going after IT's WAV writer here.
+ // For SB/GUS/etc. emulation, envelope carry should only apply when the NNA isn't set to "Note Cut".
+ // Test case: CarryNNA.it
resetAlways = (instrumentChanged || pChn->dwFlags[CHN_KEYOFF]);
} else
{
@@ -837,7 +840,7 @@
}
}
// Invalid sample ?
- if (!pSmp)
+ if(!pSmp)
{
pChn->pModSample = nullptr;
pChn->nInsVol = 0;
@@ -845,12 +848,12 @@
}
// Tone-Portamento doesn't reset the pingpong direction flag
- if (bPorta && pSmp == pChn->pModSample)
+ if(bPorta && pSmp == pChn->pModSample)
{
// If channel length is 0, we cut a previous sample using SCx. In that case, we have to update sample length, loop points, etc...
if(GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT) && pChn->nLength != 0) return;
pChn->dwFlags.reset(CHN_KEYOFF | CHN_NOTEFADE);
- pChn->dwFlags = (pChn->dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG)) | (static_cast<ChannelFlags>(pSmp->uFlags) & CHN_SAMPLEFLAGS);
+ pChn->dwFlags = (pChn->dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG)) | (pSmp->uFlags & CHN_SAMPLEFLAGS);
} else
{
pChn->dwFlags.reset(CHN_KEYOFF | CHN_NOTEFADE);
@@ -858,12 +861,12 @@
// IT compatibility tentative fix: Don't change bidi loop direction when
// no sample nor instrument is changed.
if(IsCompatibleMode(TRK_ALLTRACKERS) && pSmp == pChn->pModSample && !instrumentChanged)
- pChn->dwFlags = (pChn->dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG)) | (static_cast<ChannelFlags>(pSmp->uFlags) & CHN_SAMPLEFLAGS);
+ pChn->dwFlags = (pChn->dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG)) | (pSmp->uFlags & CHN_SAMPLEFLAGS);
else
- pChn->dwFlags = (pChn->dwFlags & CHN_CHANNELFLAGS) | (static_cast<ChannelFlags>(pSmp->uFlags) & CHN_SAMPLEFLAGS);
+ pChn->dwFlags = (pChn->dwFlags & CHN_CHANNELFLAGS) | (pSmp->uFlags & CHN_SAMPLEFLAGS);
- if (pIns)
+ if(pIns)
{
// Copy envelope flags (we actually only need the "enabled" and "pitch" flag)
pChn->VolEnv.flags = pIns->VolEnv.dwFlags;
@@ -874,11 +877,11 @@
// Test case: FilterEnvReset.it
if((pIns->PitchEnv.dwFlags & (ENV_ENABLED | ENV_FILTER)) == (ENV_ENABLED | ENV_FILTER) && !IsCompatibleMode(TRK_IMPULSETRACKER))
{
- if (!pChn->nCutOff) pChn->nCutOff = 0x7F;
+ if(!pChn->nCutOff) pChn->nCutOff = 0x7F;
}
- if (pIns->IsCutoffEnabled()) pChn->nCutOff = pIns->GetCutoff();
- if (pIns->IsResonanceEnabled()) pChn->nResonance = pIns->GetResonance();
+ if(pIns->IsCutoffEnabled()) pChn->nCutOff = pIns->GetCutoff();
+ if(pIns->IsResonanceEnabled()) pChn->nResonance = pIns->GetResonance();
}
pChn->nVolSwing = pChn->nPanSwing = 0;
pChn->nResSwing = pChn->nCutSwing = 0;
@@ -956,17 +959,17 @@
// save the note that's actually used, as it's necessary to properly calculate PPS and stuff
const int realnote = note;
- if ((pIns) && (note <= 0x80))
+ if((pIns) && (note - NOTE_MIN < CountOf(pIns->Keyboard)))
{
UINT n = pIns->Keyboard[note - NOTE_MIN];
if ((n) && (n < MAX_SAMPLES)) pSmp = &Samples[n];
note = pIns->NoteMap[note-1];
}
// Key Off
- if (note > NOTE_MAX)
+ if(note > NOTE_MAX)
{
// Key Off (+ Invalid Note for XM - TODO is this correct?)
- if (note == NOTE_KEYOFF || !(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)))
+ if(note == NOTE_KEYOFF || !(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)))
{
KeyOff(nChn);
}
@@ -1004,9 +1007,9 @@
}
}
- if (!bPorta && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MED | MOD_TYPE_MT2)))
+ if(!bPorta && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MED | MOD_TYPE_MT2)))
{
- if (pSmp)
+ if(pSmp)
{
pChn->nTranspose = pSmp->RelativeTone;
pChn->nFineTune = pSmp->nFineTune;
@@ -1056,10 +1059,10 @@
UINT period = GetPeriodFromNote(note, pChn->nFineTune, pChn->nC5Speed);
- if (!pSmp) return;
- if (period)
+ if(!pSmp) return;
+ if(period)
{
- if ((!bPorta) || (!pChn->nPeriod)) pChn->nPeriod = period;
+ if((!bPorta) || (!pChn->nPeriod)) pChn->nPeriod = period;
if(!newTuning)
{
// FT2 compatibility: Don't reset portamento target with new notes.
@@ -1070,7 +1073,7 @@
}
}
- if (!bPorta || (!pChn->nLength && !(GetType() & MOD_TYPE_S3M)))
+ if(!bPorta || (!pChn->nLength && !(GetType() & MOD_TYPE_S3M)))
{
pChn->pModSample = pSmp;
pChn->pSample = pSmp->pSample;
@@ -1078,14 +1081,14 @@
pChn->nLoopEnd = pSmp->nLength;
pChn->nLoopStart = 0;
pChn->dwFlags = (pChn->dwFlags & CHN_CHANNELFLAGS) | (static_cast<ChannelFlags>(pSmp->uFlags) & CHN_SAMPLEFLAGS);
- if (pChn->dwFlags[CHN_SUSTAINLOOP])
+ if(pChn->dwFlags[CHN_SUSTAINLOOP])
{
pChn->nLoopStart = pSmp->nSustainStart;
pChn->nLoopEnd = pSmp->nSustainEnd;
pChn->dwFlags.set(CHN_PINGPONGLOOP, pChn->dwFlags[CHN_PINGPONGSUSTAIN]);
pChn->dwFlags.set(CHN_LOOP);
if (pChn->nLength > pChn->nLoopEnd) pChn->nLength = pChn->nLoopEnd;
- } else if (pChn->dwFlags[CHN_LOOP])
+ } else if(pChn->dwFlags[CHN_LOOP])
{
pChn->nLoopStart = pSmp->nLoopStart;
pChn->nLoopEnd = pSmp->nLoopEnd;
@@ -1094,7 +1097,7 @@
pChn->nPos = 0;
pChn->nPosLo = 0;
// Handle "retrigger" waveform type
- if (pChn->nVibratoType < 4)
+ if(pChn->nVibratoType < 4)
{
// IT Compatibilty: Slightly different waveform offsets (why does MPT have two different offsets here with IT old effects enabled and disabled?)
if(!IsCompatibleMode(TRK_IMPULSETRACKER) && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS])
@@ -1108,9 +1111,8 @@
pChn->nTremoloPos = 0;
}
}
- if (pChn->nPos >= pChn->nLength) pChn->nPos = pChn->nLoopStart;
- }
- else
+ if(pChn->nPos >= pChn->nLength) pChn->nPos = pChn->nLoopStart;
+ } else
{
bPorta = false;
}
@@ -1149,7 +1151,7 @@
pChn->dwFlags.reset(CHN_EXTRALOUD | CHN_KEYOFF);
// Enable Ramping
- if (!bPorta)
+ if(!bPorta)
{
pChn->nVUMeter = 0x100;
pChn->nLeftVU = pChn->nRightVU = 0xFF;
@@ -1172,11 +1174,11 @@
}
}
- if (bResetEnv)
+ if(bResetEnv)
{
pChn->nVolSwing = pChn->nPanSwing = 0;
pChn->nResSwing = pChn->nCutSwing = 0;
- if (pIns)
+ if(pIns)
{
// IT Compatiblity: NNA is reset on every note change, not every instrument change (fixes spx-farspacedance.it).
if(IsCompatibleMode(TRK_IMPULSETRACKER)) pChn->nNNA = pIns->nNNA;
@@ -1188,13 +1190,13 @@
if(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT))
{
// Volume Swing
- if (pIns->nVolSwing)
+ if(pIns->nVolSwing)
{
const double delta = 2 * (((double) rand()) / RAND_MAX) - 1;
pChn->nVolSwing = static_cast<int32>(std::floor(delta * (IsCompatibleMode(TRK_IMPULSETRACKER) ? pChn->nInsVol : ((pChn->nVolume + 1) / 2)) * pIns->nVolSwing / 100.0));
}
// Pan Swing
- if (pIns->nPanSwing)
+ if(pIns->nPanSwing)
{
const double delta = 2 * (((double) rand()) / RAND_MAX) - 1;
pChn->nPanSwing = static_cast<int32>(std::floor(delta * (IsCompatibleMode(TRK_IMPULSETRACKER) ? 4 : 1) * pIns->nPanSwing));
@@ -1204,14 +1206,14 @@
}
}
// Cutoff Swing
- if (pIns->nCutSwing)
+ if(pIns->nCutSwing)
{
int32 d = ((int32)pIns->nCutSwing * (int32)((rand() & 0xFF) - 0x7F)) / 128;
pChn->nCutSwing = (int16)((d * pChn->nCutOff + 1) / 128);
pChn->nRestoreCutoffOnNewNote = pChn->nCutOff + 1;
}
// Resonance Swing
- if (pIns->nResSwing)
+ if(pIns->nResSwing)
{
int32 d = ((int32)pIns->nResSwing * (int32)((rand() & 0xFF) - 0x7F)) / 128;
pChn->nResSwing = (int16)((d * pChn->nResonance + 1) / 128);
@@ -1230,21 +1232,21 @@
}
}
pChn->nLeftVol = pChn->nRightVol = 0;
- bool bFlt = !m_SongFlags[SONG_MPTFILTERMODE];
+ bool useFilter = !m_SongFlags[SONG_MPTFILTERMODE];
// Setup Initial Filter for this note
- if (pIns)
+ if(pIns)
{
- if (pIns->IsResonanceEnabled())
+ if(pIns->IsResonanceEnabled())
{
pChn->nResonance = pIns->GetResonance();
- bFlt = true;
+ useFilter = true;
}
- if (pIns->IsCutoffEnabled())
+ if(pIns->IsCutoffEnabled())
{
pChn->nCutOff = pIns->GetCutoff();
- bFlt = true;
+ useFilter = true;
}
- if (bFlt && (pIns->nFilterMode != FLTMODE_UNCHANGED))
+ if(useFilter && (pIns->nFilterMode != FLTMODE_UNCHANGED))
{
pChn->nFilterMode = pIns->nFilterMode;
}
@@ -1253,7 +1255,7 @@
pChn->nVolSwing = pChn->nPanSwing = 0;
pChn->nCutSwing = pChn->nResSwing = 0;
}
- if ((pChn->nCutOff < 0x7F || IsCompatibleMode(TRK_IMPULSETRACKER)) && (bFlt))
+ if((pChn->nCutOff < 0x7F || IsCompatibleMode(TRK_IMPULSETRACKER)) && useFilter)
{
SetupChannelFilter(pChn, true);
}
@@ -2040,35 +2042,41 @@
volcmd = VOLCMD_NONE;
}
- } else
+ } else if(!IsCompatibleMode(TRK_IMPULSETRACKER))
{
+ // IT Compatibility: Effects in the volume column don't have an unified memory.
+ // Test case: VolColMemory.it
if(vol) pChn->nOldVolParam = vol; else vol = pChn->nOldVolParam;
}
switch(volcmd)
{
case VOLCMD_VOLSLIDEUP:
- VolumeSlide(pChn, vol << 4);
- break;
-
case VOLCMD_VOLSLIDEDOWN:
- VolumeSlide(pChn, vol);
+ // IT Compatibility: Volume column volume slides have their own memory
+ // Test case: VolColMemory.it
+ if(vol == 0 && IsCompatibleMode(TRK_IMPULSETRACKER))
+ {
+ vol = pChn->nOldVolColSlide;
+ if(vol == 0)
+ break;
+ } else
+ {
+ pChn->nOldVolColSlide = vol;
+ }
+ VolumeSlide(pChn, volcmd == VOLCMD_VOLSLIDEUP ? (vol << 4) : vol);
break;
case VOLCMD_FINEVOLUP:
- if (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
- {
- if (m_nTickCount == nStartTick) VolumeSlide(pChn, (vol << 4) | 0x0F);
- } else
- FineVolumeUp(pChn, vol);
+ // IT Compatibility: Volume column volume slides have their own memory
+ // Test case: VolColMemory.it
+ FineVolumeUp(pChn, vol, IsCompatibleMode(TRK_IMPULSETRACKER));
break;
case VOLCMD_FINEVOLDOWN:
- if (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
- {
- if (m_nTickCount == nStartTick) VolumeSlide(pChn, 0xF0 | vol);
- } else
- FineVolumeDown(pChn, vol);
+ // IT Compatibility: Volume column volume slides have their own memory
+ // Test case: VolColMemory.it
+ FineVolumeDown(pChn, vol, IsCompatibleMode(TRK_IMPULSETRACKER));
break;
case VOLCMD_VIBRATOSPEED:
@@ -3069,7 +3077,7 @@
{
if (param & 0xF0) //Fine upslide
{
- FineVolumeUp(pChn, (param >> 4));
+ FineVolumeUp(pChn, (param >> 4), false);
return;
} else //Slide -15
{
@@ -3083,7 +3091,7 @@
{
if (param & 0x0F) //Fine downslide
{
- FineVolumeDown(pChn, (param & 0x0F));
+ FineVolumeDown(pChn, (param & 0x0F), false);
return;
} else //Slide +15
{
@@ -3198,14 +3206,17 @@
}
-void CSoundFile::FineVolumeUp(ModChannel *pChn, UINT param)
-//---------------------------------------------------------
+void CSoundFile::FineVolumeUp(ModChannel *pChn, UINT param, bool volCol)
+//----------------------------------------------------------------------
{
if(GetType() == MOD_TYPE_XM)
{
// FT2 compatibility: EAx / EBx memory is not linked
// Test case: FineVol-LinkMem.xm
if(param) pChn->nOldFineVolUpDown = (param << 4) | (pChn->nOldFineVolUpDown & 0x0F); else param = (pChn->nOldFineVolUpDown >> 4);
+ } else if(volCol)
+ {
+ if(param) pChn->nOldVolColSlide = param; else param = pChn->nOldVolColSlide;
} else
{
if(param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
@@ -3220,14 +3231,17 @@
}
-void CSoundFile::FineVolumeDown(ModChannel *pChn, UINT param)
-//-----------------------------------------------------------
+void CSoundFile::FineVolumeDown(ModChannel *pChn, UINT param, bool volCol)
+//------------------------------------------------------------------------
{
if(GetType() == MOD_TYPE_XM)
{
// FT2 compatibility: EAx / EBx memory is not linked
// Test case: FineVol-LinkMem.xm
if(param) pChn->nOldFineVolUpDown = param | (pChn->nOldFineVolUpDown & 0xF0); else param = (pChn->nOldFineVolUpDown & 0x0F);
+ } else if(volCol)
+ {
+ if(param) pChn->nOldVolColSlide = param; else param = pChn->nOldVolColSlide;
} else
{
if(param) pChn->nOldFineVolUpDown = param; else param = pChn->nOldFineVolUpDown;
@@ -3339,9 +3353,9 @@
// E9x: Retrig
case 0x90: RetrigNote(nChn, param); break;
// EAx: Fine Volume Up
- case 0xA0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(pChn, param); break;
+ case 0xA0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(pChn, param, false); break;
// EBx: Fine Volume Down
- case 0xB0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(pChn, param); break;
+ case 0xB0: if ((param) || (m_nType & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(pChn, param, false); break;
// ECx: Note Cut
case 0xC0: NoteCut(nChn, param); break;
// EDx: Note Delay
Modified: trunk/OpenMPT/soundlib/Sndfile.h
===================================================================
--- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-21 15:24:54 UTC (rev 1544)
+++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-22 22:55:15 UTC (rev 1545)
@@ -574,8 +574,8 @@
void VolumeSlide(ModChannel *pChn, UINT param);
void PanningSlide(ModChannel *pChn, UINT param, bool memory = true);
void ChannelVolSlide(ModChannel *pChn, UINT param);
- void FineVolumeUp(ModChannel *pChn, UINT param);
- void FineVolumeDown(ModChannel *pChn, UINT param);
+ void FineVolumeUp(ModChannel *pChn, UINT param, bool volCol);
+ void FineVolumeDown(ModChannel *pChn, UINT param, bool volCol);
void Tremolo(ModChannel *pChn, UINT param);
void Panbrello(ModChannel *pChn, UINT param);
void RetrigNote(CHANNELINDEX nChn, int param, UINT offset=0); //rewbs.volOffset: added last param
Modified: trunk/OpenMPT/soundlib/modcommand.h
===================================================================
--- trunk/OpenMPT/soundlib/modcommand.h 2013-02-21 15:24:54 UTC (rev 1544)
+++ trunk/OpenMPT/soundlib/modcommand.h 2013-02-22 22:55:15 UTC (rev 1545)
@@ -62,11 +62,12 @@
void Clear() { memset(this, 0, sizeof(ModCommand)); }
// Returns true if modcommand is empty, false otherwise.
- // If ignoreEffectValues is true (default), effect values are ignored are ignored if there is no effect command present.
+ // If ignoreEffectValues is true (default), effect values are ignored if there is no effect command present.
bool IsEmpty(const bool ignoreEffectValues = true) const
{
if(ignoreEffectValues)
- return (this->note == 0 && this->instr == 0 && this->volcmd == 0 && this->command == 0);
+ return *reinterpret_cast<const uint32 *>(this) == 0; // First four bytes contain note, instr, volcmd and command
+ //return (this->note == 0 && this->instr == 0 && this->volcmd == VOLCMD_NONE && this->command == CMD_NONE);
else
return (*this == Empty());
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|