#include "stdafx.h"
#include "Sndfile.h"
#include "../common/mptStringBuffer.h"
#include "../common/version.h"
OPENMPT_NAMESPACE_BEGIN
struct UpgradePatternData
{
UpgradePatternData(CSoundFile &sf)
: sndFile(sf)
, compatPlay(sf.m_playBehaviour[MSF_COMPATIBLE_PLAY]) { }
void operator() (ModCommand &m)
{
const CHANNELINDEX curChn = chn;
chn++;
if(chn >= sndFile.GetNumChannels())
{
chn = 0;
}
if(m.IsPcNote())
{
return;
}
const auto version = sndFile.m_dwLastSavedWithVersion;
const auto modType = sndFile.GetType();
if(modType == MOD_TYPE_S3M)
{
if(version < MAKE_VERSION_NUMERIC(1, 19, 00, 00) && m.command == CMD_GLOBALVOLUME)
{
LimitMax(m.param, ModCommand::PARAM(64));
}
}
else if(modType & (MOD_TYPE_IT | MOD_TYPE_MPT))
{
if(version < MAKE_VERSION_NUMERIC(1, 17, 03, 02) ||
(!compatPlay && version < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
{
if(m.command == CMD_GLOBALVOLUME)
{
LimitMax(m.param, ModCommand::PARAM(128));
}
else if(m.command == CMD_S3MCMDEX)
{
if(m.param == 0xC0)
{
m.command = CMD_NONE;
m.note = NOTE_NOTECUT;
} else if(m.param == 0xD0)
{
m.command = CMD_NONE;
}
}
}
const bool noteVolSlide =
(version < MAKE_VERSION_NUMERIC(1, 18, 00, 00) ||
(!compatPlay && version < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
&&
(m.command == CMD_VOLUMESLIDE || m.command == CMD_VIBRATOVOL || m.command == CMD_TONEPORTAVOL || m.command == CMD_PANNINGSLIDE);
const bool chanVolSlide =
(version < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
&&
(m.command == CMD_GLOBALVOLSLIDE || m.command == CMD_CHANNELVOLSLIDE);
if(noteVolSlide || chanVolSlide)
{
if((m.param & 0x0F) != 0x00 && (m.param & 0x0F) != 0x0F && (m.param & 0xF0) != 0x00 && (m.param & 0xF0) != 0xF0)
{
m.param &= 0x0F;
}
}
if(version < MAKE_VERSION_NUMERIC(1, 22, 01, 04)
&& version != MAKE_VERSION_NUMERIC(1, 22, 00, 00)) {
if(sndFile.GetNumInstruments() && m.instr > sndFile.GetNumInstruments() && !compatPlay)
{
m.volcmd = VOLCMD_VOLUME;
m.vol = 0;
}
}
}
else if(modType == MOD_TYPE_XM)
{
if(((version >= MAKE_VERSION_NUMERIC(1, 17, 03, 02) && compatPlay) || (version >= MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
&& version < MAKE_VERSION_NUMERIC(1, 24, 02, 02)
&& m.command == CMD_GLOBALVOLUME
&& m.param > 64)
{
m.command = CMD_NONE;
}
if(version < MAKE_VERSION_NUMERIC(1, 19, 00, 00)
|| (!compatPlay && version < MAKE_VERSION_NUMERIC(1, 20, 00, 00)))
{
if(m.command == CMD_OFFSET && m.volcmd == VOLCMD_TONEPORTAMENTO)
{
m.command = CMD_NONE;
}
}
if(version < MAKE_VERSION_NUMERIC(1, 20, 01, 10)
&& m.volcmd == VOLCMD_TONEPORTAMENTO && m.command == CMD_TONEPORTAMENTO
&& (m.vol != 0 || compatPlay) && m.param != 0)
{
m.volcmd = VOLCMD_NONE;
const uint16 param = static_cast<uint16>(m.param) + static_cast<uint16>(m.vol << 4);
m.param = mpt::saturate_cast<ModCommand::PARAM>(param);
}
if(version < MAKE_VERSION_NUMERIC(1, 22, 07, 09)
&& m.command == CMD_SPEED && m.param == 0)
{
m.command = CMD_NONE;
}
}
if(version < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
{
const bool fixS6x = (m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0x60);
const bool fixX6x = (m.command == CMD_XFINEPORTAUPDOWN && (m.param & 0xF0) == 0x60
&& (!(compatPlay && modType == MOD_TYPE_XM) || version < MAKE_VERSION_NUMERIC(1, 18, 00, 00)));
if(fixS6x || fixX6x)
{
for(ModCommand *fixCmd = (&m) - curChn; fixCmd < &m; fixCmd++)
{
if((fixCmd->command == CMD_S3MCMDEX || fixCmd->command == CMD_XFINEPORTAUPDOWN) && (fixCmd->param & 0xF0) == 0x60)
{
fixCmd->command = CMD_NONE;
}
}
}
if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xE0)
{
for(ModCommand *fixCmd = (&m) - curChn; fixCmd < &m; fixCmd++)
{
if(fixCmd->command == CMD_S3MCMDEX && (fixCmd->param & 0xF0) == 0xE0)
{
fixCmd->command = CMD_NONE;
}
}
}
}
if(m.volcmd == VOLCMD_VIBRATODEPTH
&& version < MAKE_VERSION_NUMERIC(1, 27, 00, 37)
&& version != MAKE_VERSION_NUMERIC(1, 27, 00, 00))
{
if(m.command == CMD_VIBRATOVOL && m.vol > 0)
{
m.command = CMD_VOLUMESLIDE;
} else if((m.command == CMD_VIBRATO || m.command == CMD_FINEVIBRATO) && (m.param & 0x0F) == 0)
{
m.command = CMD_VIBRATO;
m.param |= (m.vol & 0x0F);
m.volcmd = VOLCMD_NONE;
} else if(m.command == CMD_VIBRATO || m.command == CMD_VIBRATOVOL || m.command == CMD_FINEVIBRATO)
{
m.volcmd = VOLCMD_NONE;
}
}
if(modType != MOD_TYPE_MPT && m.volcmd == VOLCMD_OFFSET && m.command == CMD_NONE)
{
m.command = CMD_OFFSET;
m.param = m.vol << 3;
m.volcmd = VOLCMD_NONE;
}
}
const CSoundFile &sndFile;
CHANNELINDEX chn = 0;
const bool compatPlay;
};
void CSoundFile::UpgradeModule()
{
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 02, 46) && m_dwLastSavedWithVersion != MAKE_VERSION_NUMERIC(1, 17, 00, 00))
{
m_playBehaviour.reset(MSF_COMPATIBLE_PLAY);
}
const bool compatModeIT = m_playBehaviour[MSF_COMPATIBLE_PLAY] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT));
const bool compatModeXM = m_playBehaviour[MSF_COMPATIBLE_PLAY] && GetType() == MOD_TYPE_XM;
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 00, 00))
{
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
{
ModInstrument *ins = Instruments[i];
ins->nVolSwing = static_cast<uint8>(std::min<uint32>(ins->nVolSwing * 100 / 64, 100));
if(!compatModeIT || m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 18, 00, 00))
{
ins->nPPS = (ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2;
}
if(!compatModeIT || m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 03, 02))
{
ins->GetEnvelope(ENV_PITCH).Convert(MOD_TYPE_XM, GetType());
}
if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 17, 00, 00) && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 02, 50))
{
if(ins->nMixPlug && ins->HasValidMIDIChannel())
{
m_playBehaviour.set(kMIDICCBugEmulation);
}
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 02, 50) && (ins->nVolSwing | ins->nPanSwing | ins->nCutSwing | ins->nResSwing))
{
m_playBehaviour.set(kMPTOldSwingBehaviour);
break;
}
}
if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 03, 02) || !compatModeIT))
{
for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
{
if(Samples[i].nVibSweep == 0 && (Samples[i].nVibDepth | Samples[i].nVibRate))
{
Samples[i].nVibSweep = 255;
}
}
}
m_MidiCfg.UpgradeMacros();
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 20, 02, 10)
&& m_dwLastSavedWithVersion != MAKE_VERSION_NUMERIC(1, 20, 00, 00)
&& (GetType() & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT)))
{
bool instrPlugs = false;
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
{
if(Instruments[i] != nullptr && Instruments[i]->nMidiChannel != MidiNoChannel)
{
Instruments[i]->midiPWD = 13;
instrPlugs = true;
}
}
if(instrPlugs)
{
m_playBehaviour.set(kOldMIDIPitchBends);
}
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 22, 03, 12)
&& m_dwLastSavedWithVersion != MAKE_VERSION_NUMERIC(1, 22, 00, 00)
&& (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
&& (m_playBehaviour[MSF_COMPATIBLE_PLAY] || m_playBehaviour[kMPTOldSwingBehaviour]))
{
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
{
if(Instruments[i] != nullptr && Instruments[i]->nPanSwing != 0 && Instruments[i]->PanEnv.dwFlags[ENV_ENABLED])
{
Instruments[i]->nPanSwing = 0;
}
}
}
#ifndef NO_PLUGINS
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 22, 07, 01))
{
for(auto &plugin : m_MixPlugins)
{
#if defined(MODPLUG_TRACKER)
const std::string name = mpt::ToCharset(mpt::CharsetUTF8, mpt::CharsetLocale, plugin.Info.szLibraryName);
#else
const std::string name = mpt::ToCharset(mpt::CharsetUTF8, mpt::CharsetWindows1252, plugin.Info.szLibraryName);
#endif
mpt::String::Copy(plugin.Info.szLibraryName, name);
}
}
#endif
if(GetType() == MOD_TYPE_XM)
{
if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 22, 07, 19)
&& m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 23, 01, 04)
&& GetMixLevels() == mixLevelsCompatible)
{
SetMixLevels(mixLevelsCompatibleFT2);
}
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 25, 00, 07) && m_dwLastSavedWithVersion != MAKE_VERSION_NUMERIC(1, 25, 00, 00))
{
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
{
if(Instruments[i] != nullptr && Instruments[i]->nVolSwing != 0 && Instruments[i]->nMidiChannel != MidiNoChannel)
{
bool hasSample = false;
for(auto smp : Instruments[i]->Keyboard)
{
if(smp != 0)
{
hasSample = true;
break;
}
}
if(!hasSample)
{
Instruments[i]->nVolSwing = 0;
}
}
}
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00))
{
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
{
ModInstrument *ins = Instruments[i];
ins->nPPS = (ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2;
if(!compatModeIT || m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 18, 00, 00))
{
ins->nPanSwing = (ins->nPanSwing + 3) / 4u;
}
}
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 28, 00, 12))
{
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
{
if(Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET)
{
m_playBehaviour.set(kLegacyReleaseNode);
break;
}
}
}
Patterns.ForEachModCommand(UpgradePatternData(*this));
struct PlayBehaviourVersion
{
PlayBehaviour behaviour;
Version version;
};
if(compatModeIT && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00))
{
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kTempoClamp, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPerChannelGlobalVolSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPanOverride, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITInstrWithoutNote, MAKE_VERSION_NUMERIC(1, 17, 02, 46) },
{ kITVolColFinePortamento, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITArpeggio, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITOutOfRangeDelay, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPortaMemoryShare, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPatternLoopTargetReset, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITFT2PatternLoop, MAKE_VERSION_NUMERIC(1, 17, 02, 49) },
{ kITPingPongNoReset, MAKE_VERSION_NUMERIC(1, 17, 02, 51) },
{ kITEnvelopeReset, MAKE_VERSION_NUMERIC(1, 17, 02, 51) },
{ kITClearOldNoteAfterCut, MAKE_VERSION_NUMERIC(1, 17, 02, 52) },
{ kITVibratoTremoloPanbrello, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITTremor, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITRetrigger, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITMultiSampleBehaviour, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITPortaTargetReached, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITPatternLoopBreak, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITOffset, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITSwingBehaviour, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kITNNAReset, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kITSCxStopsSample, MAKE_VERSION_NUMERIC(1, 18, 00, 01) },
{ kITEnvelopePositionHandling, MAKE_VERSION_NUMERIC(1, 18, 01, 00) },
{ kITPortamentoInstrument, MAKE_VERSION_NUMERIC(1, 19, 00, 01) },
{ kITPingPongMode, MAKE_VERSION_NUMERIC(1, 19, 00, 21) },
{ kITRealNoteMapping, MAKE_VERSION_NUMERIC(1, 19, 00, 30) },
{ kITHighOffsetNoRetrig, MAKE_VERSION_NUMERIC(1, 20, 00, 14) },
{ kITFilterBehaviour, MAKE_VERSION_NUMERIC(1, 20, 00, 35) },
{ kITNoSurroundPan, MAKE_VERSION_NUMERIC(1, 20, 00, 53) },
{ kITShortSampleRetrig, MAKE_VERSION_NUMERIC(1, 20, 00, 54) },
{ kITPortaNoNote, MAKE_VERSION_NUMERIC(1, 20, 00, 56) },
{ kRowDelayWithNoteDelay, MAKE_VERSION_NUMERIC(1, 20, 00, 76) },
{ kITDontResetNoteOffOnPorta, MAKE_VERSION_NUMERIC(1, 20, 02, 06) },
{ kITVolColMemory, MAKE_VERSION_NUMERIC(1, 21, 01, 16) },
{ kITPortamentoSwapResetsPos, MAKE_VERSION_NUMERIC(1, 21, 01, 25) },
{ kITEmptyNoteMapSlot, MAKE_VERSION_NUMERIC(1, 21, 01, 25) },
{ kITFirstTickHandling, MAKE_VERSION_NUMERIC(1, 22, 07, 09) },
{ kITSampleAndHoldPanbrello, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
{ kITClearPortaTarget, MAKE_VERSION_NUMERIC(1, 23, 04, 03) },
{ kITPanbrelloHold, MAKE_VERSION_NUMERIC(1, 24, 01, 06) },
{ kITPanningReset, MAKE_VERSION_NUMERIC(1, 24, 01, 06) },
{ kITPatternLoopWithJumps, MAKE_VERSION_NUMERIC(1, 25, 00, 19) },
};
for(const auto &b : behaviours)
{
m_playBehaviour.set(b.behaviour, (m_dwLastSavedWithVersion >= b.version || m_dwLastSavedWithVersion == b.version.Masked(0xFFFF0000u)));
}
} else if(compatModeXM && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00))
{
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kTempoClamp, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPerChannelGlobalVolSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kPanOverride, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kITFT2PatternLoop, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2Arpeggio, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2Retrigger, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2VolColVibrato, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2PortaNoNote, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2KeyOff, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2PanSlide, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2OffsetOutOfRange, MAKE_VERSION_NUMERIC(1, 17, 03, 02) },
{ kFT2RestrictXCommand, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2RetrigWithNoteDelay, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2SetPanEnvPos, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kFT2PortaIgnoreInstr, MAKE_VERSION_NUMERIC(1, 18, 00, 01) },
{ kFT2VolColMemory, MAKE_VERSION_NUMERIC(1, 18, 01, 00) },
{ kFT2LoopE60Restart, MAKE_VERSION_NUMERIC(1, 18, 02, 01) },
{ kFT2ProcessSilentChannels, MAKE_VERSION_NUMERIC(1, 18, 02, 01) },
{ kFT2ReloadSampleSettings, MAKE_VERSION_NUMERIC(1, 20, 00, 36) },
{ kFT2PortaDelay, MAKE_VERSION_NUMERIC(1, 20, 00, 40) },
{ kFT2Transpose, MAKE_VERSION_NUMERIC(1, 20, 00, 62) },
{ kFT2PatternLoopWithJumps, MAKE_VERSION_NUMERIC(1, 20, 00, 69) },
{ kFT2PortaTargetNoReset, MAKE_VERSION_NUMERIC(1, 20, 00, 69) },
{ kFT2EnvelopeEscape, MAKE_VERSION_NUMERIC(1, 20, 00, 77) },
{ kFT2Tremor, MAKE_VERSION_NUMERIC(1, 20, 01, 11) },
{ kFT2OutOfRangeDelay, MAKE_VERSION_NUMERIC(1, 20, 02, 02) },
{ kFT2Periods, MAKE_VERSION_NUMERIC(1, 22, 03, 01) },
{ kFT2PanWithDelayedNoteOff, MAKE_VERSION_NUMERIC(1, 22, 03, 02) },
{ kFT2VolColDelay, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
{ kFT2FinetunePrecision, MAKE_VERSION_NUMERIC(1, 22, 07, 19) },
};
for(const auto &b : behaviours)
{
m_playBehaviour.set(b.behaviour, m_dwLastSavedWithVersion >= b.version);
}
}
if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
{
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kITInstrWithNoteOff, MAKE_VERSION_NUMERIC(1, 26, 00, 01) },
{ kITMultiSampleInstrumentNumber, MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
{ kITInstrWithNoteOffOldEffects, MAKE_VERSION_NUMERIC(1, 28, 02, 06) },
};
for(const auto &b : behaviours)
{
if(m_dwLastSavedWithVersion < b.version.Masked(0xFFFF0000u))
m_playBehaviour.reset(b.behaviour);
else if(m_dwLastSavedWithVersion > b.version.Masked(0xFFFF0000u) && m_dwLastSavedWithVersion < b.version)
m_playBehaviour.reset(b.behaviour);
}
} else if(GetType() == MOD_TYPE_XM)
{
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kFT2NoteOffFlags, MAKE_VERSION_NUMERIC(1, 27, 00, 27) },
{ kRowDelayWithNoteDelay, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2TremoloRampWaveform, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2PortaUpDownMemory, MAKE_VERSION_NUMERIC(1, 27, 00, 37) },
{ kFT2PanSustainRelease, MAKE_VERSION_NUMERIC(1, 28, 00, 09) },
{ kFT2NoteDelayWithoutInstr, MAKE_VERSION_NUMERIC(1, 28, 00, 44) },
};
for(const auto &b : behaviours)
{
if(m_dwLastSavedWithVersion < b.version)
m_playBehaviour.reset(b.behaviour);
}
} else if(GetType() == MOD_TYPE_S3M)
{
static constexpr PlayBehaviourVersion behaviours[] =
{
{ kST3NoMutedChannels, MAKE_VERSION_NUMERIC(1, 18, 00, 00) },
{ kST3EffectMemory, MAKE_VERSION_NUMERIC(1, 20, 00, 00) },
{ kRowDelayWithNoteDelay, MAKE_VERSION_NUMERIC(1, 20, 00, 00) },
{ kST3PortaSampleChange, MAKE_VERSION_NUMERIC(1, 22, 00, 00) },
{ kST3VibratoMemory, MAKE_VERSION_NUMERIC(1, 26, 00, 00) },
{ kITPanbrelloHold, MAKE_VERSION_NUMERIC(1, 26, 00, 00) },
{ KST3PortaAfterArpeggio, MAKE_VERSION_NUMERIC(1, 27, 00, 00) },
{ kST3OffsetWithoutInstrument, MAKE_VERSION_NUMERIC(1, 28, 00, 00) },
};
for(const auto &b : behaviours)
{
if(m_dwLastSavedWithVersion < b.version)
m_playBehaviour.reset(b.behaviour);
}
}
if(GetType() == MOD_TYPE_XM && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 19, 00, 00))
{
m_playBehaviour.set(kFT2NoteDelayWithoutInstr);
}
if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 27, 00, 27) && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 27, 00, 49))
{
for(int i = 0; i < 5; i++)
{
m_playBehaviour.set(kFT2NoteOffFlags + i, m_playBehaviour[kST3NoMutedChannels + i]);
m_playBehaviour.reset(kST3NoMutedChannels + i);
}
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 00, 00))
{
m_playBehaviour.set(kTempoClamp);
} else if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 17, 00, 00) && m_dwLastSavedWithVersion <= MAKE_VERSION_NUMERIC(1, 20, 01, 03) && m_dwLastSavedWithVersion != MAKE_VERSION_NUMERIC(1, 20, 00, 00))
{
m_playBehaviour.set(kSlidesAtSpeed1);
}
if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 24, 00, 00))
{
m_playBehaviour.reset(kHertzInLinearMode);
} else if(m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 24, 00, 00) && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 26, 00, 00) && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)))
{
m_playBehaviour.set(kHertzInLinearMode);
}
if(m_playBehaviour[kITEnvelopePositionHandling]
&& m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 23, 01, 02) && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 28, 00, 43))
{
for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
{
if(Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET
&& Instruments[i]->VolEnv.dwFlags[ENV_SUSTAIN]
&& Instruments[i]->VolEnv.nReleaseNode > Instruments[i]->VolEnv.nSustainEnd)
{
m_playBehaviour.set(kReleaseNodePastSustainBug);
break;
}
}
}
}
OPENMPT_NAMESPACE_END