1
0

UpgradeModule.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. /*
  2. * UpdateModule.cpp
  3. * ----------------
  4. * Purpose: Compensate for playback bugs of previous OpenMPT versions during import
  5. * by rewriting patterns / samples / instruments or enabling / disabling specific compatibility flags
  6. * Notes : (currently none)
  7. * Authors: OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include "Sndfile.h"
  12. #include "plugins/PluginManager.h"
  13. #include "../common/mptStringBuffer.h"
  14. #include "../common/version.h"
  15. OPENMPT_NAMESPACE_BEGIN
  16. struct UpgradePatternData
  17. {
  18. UpgradePatternData(CSoundFile &sf)
  19. : sndFile(sf)
  20. , compatPlay(sf.m_playBehaviour[MSF_COMPATIBLE_PLAY]) { }
  21. void operator() (ModCommand &m)
  22. {
  23. const CHANNELINDEX curChn = chn;
  24. chn++;
  25. if(chn >= sndFile.GetNumChannels())
  26. {
  27. chn = 0;
  28. }
  29. if(m.IsPcNote())
  30. {
  31. return;
  32. }
  33. const auto version = sndFile.m_dwLastSavedWithVersion;
  34. const auto modType = sndFile.GetType();
  35. if(modType == MOD_TYPE_S3M)
  36. {
  37. // Out-of-range global volume commands should be ignored in S3M. Fixed in OpenMPT 1.19 (r831).
  38. // So for tracks made with older versions of OpenMPT, we limit invalid global volume commands.
  39. if(version < MPT_V("1.19.00.00") && m.command == CMD_GLOBALVOLUME)
  40. {
  41. LimitMax(m.param, ModCommand::PARAM(64));
  42. }
  43. }
  44. else if(modType & (MOD_TYPE_IT | MOD_TYPE_MPT))
  45. {
  46. if(version < MPT_V("1.17.03.02") ||
  47. (!compatPlay && version < MPT_V("1.20.00.00")))
  48. {
  49. if(m.command == CMD_GLOBALVOLUME)
  50. {
  51. // Out-of-range global volume commands should be ignored in IT.
  52. // OpenMPT 1.17.03.02 fixed this in compatible mode, OpenMPT 1.20 fixes it in normal mode as well.
  53. // So for tracks made with older versions than OpenMPT 1.17.03.02 or tracks made with 1.17.03.02 <= version < 1.20, we limit invalid global volume commands.
  54. LimitMax(m.param, ModCommand::PARAM(128));
  55. }
  56. // SC0 and SD0 should be interpreted as SC1 and SD1 in IT files.
  57. // OpenMPT 1.17.03.02 fixed this in compatible mode, OpenMPT 1.20 fixes it in normal mode as well.
  58. else if(m.command == CMD_S3MCMDEX)
  59. {
  60. if(m.param == 0xC0)
  61. {
  62. m.command = CMD_NONE;
  63. m.note = NOTE_NOTECUT;
  64. } else if(m.param == 0xD0)
  65. {
  66. m.command = CMD_NONE;
  67. }
  68. }
  69. }
  70. // In the IT format, slide commands with both nibbles set should be ignored.
  71. // For note volume slides, OpenMPT 1.18 fixes this in compatible mode, OpenMPT 1.20 fixes this in normal mode as well.
  72. const bool noteVolSlide =
  73. (version < MPT_V("1.18.00.00") ||
  74. (!compatPlay && version < MPT_V("1.20.00.00")))
  75. &&
  76. (m.command == CMD_VOLUMESLIDE || m.command == CMD_VIBRATOVOL || m.command == CMD_TONEPORTAVOL || m.command == CMD_PANNINGSLIDE);
  77. // OpenMPT 1.20 also fixes this for global volume and channel volume slides.
  78. const bool chanVolSlide =
  79. (version < MPT_V("1.20.00.00"))
  80. &&
  81. (m.command == CMD_GLOBALVOLSLIDE || m.command == CMD_CHANNELVOLSLIDE);
  82. if(noteVolSlide || chanVolSlide)
  83. {
  84. if((m.param & 0x0F) != 0x00 && (m.param & 0x0F) != 0x0F && (m.param & 0xF0) != 0x00 && (m.param & 0xF0) != 0xF0)
  85. {
  86. if(m.command == CMD_GLOBALVOLSLIDE)
  87. m.param &= 0xF0;
  88. else
  89. m.param &= 0x0F;
  90. }
  91. }
  92. if(version < MPT_V("1.22.01.04")
  93. && version != MPT_V("1.22.00.00")) // Ignore compatibility export
  94. {
  95. // OpenMPT 1.22.01.04 fixes illegal (out of range) instrument numbers; they should do nothing. In previous versions, they stopped the playing sample.
  96. if(sndFile.GetNumInstruments() && m.instr > sndFile.GetNumInstruments() && !compatPlay)
  97. {
  98. m.volcmd = VOLCMD_VOLUME;
  99. m.vol = 0;
  100. }
  101. }
  102. // Command I11 accidentally behaved the same as command I00 with compatible IT tremor and old effects disabled
  103. if(m.command == CMD_TREMOR && m.param == 0x11 && version < MPT_V("1.29.12.02") && sndFile.m_playBehaviour[kITTremor] && !sndFile.m_SongFlags[SONG_ITOLDEFFECTS])
  104. {
  105. m.param = 0;
  106. }
  107. }
  108. else if(modType == MOD_TYPE_XM)
  109. {
  110. // Something made be believe that out-of-range global volume commands are ignored in XM
  111. // just like they are ignored in IT, but apparently they are not. Aaaaaargh!
  112. if(((version >= MPT_V("1.17.03.02") && compatPlay) || (version >= MPT_V("1.20.00.00")))
  113. && version < MPT_V("1.24.02.02")
  114. && m.command == CMD_GLOBALVOLUME
  115. && m.param > 64)
  116. {
  117. m.command = CMD_NONE;
  118. }
  119. if(version < MPT_V("1.19.00.00")
  120. || (!compatPlay && version < MPT_V("1.20.00.00")))
  121. {
  122. if(m.command == CMD_OFFSET && m.volcmd == VOLCMD_TONEPORTAMENTO)
  123. {
  124. // If there are both a portamento and an offset effect, the portamento should be preferred in XM files.
  125. // OpenMPT 1.19 fixed this in compatible mode, OpenMPT 1.20 fixes it in normal mode as well.
  126. m.command = CMD_NONE;
  127. }
  128. }
  129. if(version < MPT_V("1.20.01.10")
  130. && m.volcmd == VOLCMD_TONEPORTAMENTO && m.command == CMD_TONEPORTAMENTO
  131. && (m.vol != 0 || compatPlay) && m.param != 0)
  132. {
  133. // Mx and 3xx on the same row does weird things in FT2: 3xx is completely ignored and the Mx parameter is doubled. Fixed in revision 1312 / OpenMPT 1.20.01.10
  134. // Previously the values were just added up, so let's fix this!
  135. m.volcmd = VOLCMD_NONE;
  136. const uint16 param = static_cast<uint16>(m.param) + static_cast<uint16>(m.vol << 4);
  137. m.param = mpt::saturate_cast<ModCommand::PARAM>(param);
  138. }
  139. if(version < MPT_V("1.22.07.09")
  140. && m.command == CMD_SPEED && m.param == 0)
  141. {
  142. // OpenMPT can emulate FT2's F00 behaviour now.
  143. m.command = CMD_NONE;
  144. }
  145. }
  146. if(version < MPT_V("1.20.00.00"))
  147. {
  148. // Pattern Delay fixes
  149. const bool fixS6x = (m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0x60);
  150. // We also fix X6x commands in hacked XM files, since they are treated identically to the S6x command in IT/S3M files.
  151. // We don't treat them in files made with OpenMPT 1.18+ that have compatible play enabled, though, since they are ignored there anyway.
  152. const bool fixX6x = (m.command == CMD_XFINEPORTAUPDOWN && (m.param & 0xF0) == 0x60
  153. && (!(compatPlay && modType == MOD_TYPE_XM) || version < MPT_V("1.18.00.00")));
  154. if(fixS6x || fixX6x)
  155. {
  156. // OpenMPT 1.20 fixes multiple fine pattern delays on the same row. Previously, only the last command was considered,
  157. // but all commands should be added up. Since Scream Tracker 3 itself doesn't support S6x, we also use Impulse Tracker's behaviour here,
  158. // since we can assume that most S3Ms that make use of S6x were composed with Impulse Tracker.
  159. for(ModCommand *fixCmd = (&m) - curChn; fixCmd < &m; fixCmd++)
  160. {
  161. if((fixCmd->command == CMD_S3MCMDEX || fixCmd->command == CMD_XFINEPORTAUPDOWN) && (fixCmd->param & 0xF0) == 0x60)
  162. {
  163. fixCmd->command = CMD_NONE;
  164. }
  165. }
  166. }
  167. if(m.command == CMD_S3MCMDEX && (m.param & 0xF0) == 0xE0)
  168. {
  169. // OpenMPT 1.20 fixes multiple pattern delays on the same row. Previously, only the *last* command was considered,
  170. // but Scream Tracker 3 and Impulse Tracker only consider the *first* command.
  171. for(ModCommand *fixCmd = (&m) - curChn; fixCmd < &m; fixCmd++)
  172. {
  173. if(fixCmd->command == CMD_S3MCMDEX && (fixCmd->param & 0xF0) == 0xE0)
  174. {
  175. fixCmd->command = CMD_NONE;
  176. }
  177. }
  178. }
  179. }
  180. if(m.volcmd == VOLCMD_VIBRATODEPTH
  181. && version < MPT_V("1.27.00.37")
  182. && version != MPT_V("1.27.00.00"))
  183. {
  184. // Fix handling of double vibrato commands - previously only one of them was applied at a time
  185. if(m.command == CMD_VIBRATOVOL && m.vol > 0)
  186. {
  187. m.command = CMD_VOLUMESLIDE;
  188. } else if((m.command == CMD_VIBRATO || m.command == CMD_FINEVIBRATO) && (m.param & 0x0F) == 0)
  189. {
  190. m.command = CMD_VIBRATO;
  191. m.param |= (m.vol & 0x0F);
  192. m.volcmd = VOLCMD_NONE;
  193. } else if(m.command == CMD_VIBRATO || m.command == CMD_VIBRATOVOL || m.command == CMD_FINEVIBRATO)
  194. {
  195. m.volcmd = VOLCMD_NONE;
  196. }
  197. }
  198. // Volume column offset in IT/XM is bad, mkay?
  199. if(modType != MOD_TYPE_MPT && m.volcmd == VOLCMD_OFFSET && m.command == CMD_NONE)
  200. {
  201. m.command = CMD_OFFSET;
  202. m.param = m.vol << 3;
  203. m.volcmd = VOLCMD_NONE;
  204. }
  205. // Previously CMD_OFFSET simply overrode VOLCMD_OFFSET, now they work together as a combined command
  206. if(m.volcmd == VOLCMD_OFFSET && m.command == CMD_OFFSET && version < MPT_V("1.30.00.14"))
  207. {
  208. if(m.param != 0 || m.vol == 0)
  209. m.volcmd = VOLCMD_NONE;
  210. else
  211. m.command = CMD_NONE;
  212. }
  213. }
  214. const CSoundFile &sndFile;
  215. CHANNELINDEX chn = 0;
  216. const bool compatPlay;
  217. };
  218. void CSoundFile::UpgradeModule()
  219. {
  220. if(m_dwLastSavedWithVersion < MPT_V("1.17.02.46") && m_dwLastSavedWithVersion != MPT_V("1.17.00.00"))
  221. {
  222. // Compatible playback mode didn't exist in earlier versions, so definitely disable it.
  223. m_playBehaviour.reset(MSF_COMPATIBLE_PLAY);
  224. }
  225. const bool compatModeIT = m_playBehaviour[MSF_COMPATIBLE_PLAY] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT));
  226. const bool compatModeXM = m_playBehaviour[MSF_COMPATIBLE_PLAY] && GetType() == MOD_TYPE_XM;
  227. if(m_dwLastSavedWithVersion < MPT_V("1.20.00.00"))
  228. {
  229. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
  230. {
  231. ModInstrument *ins = Instruments[i];
  232. // Previously, volume swing values ranged from 0 to 64. They should reach from 0 to 100 instead.
  233. ins->nVolSwing = static_cast<uint8>(std::min(static_cast<uint32>(ins->nVolSwing * 100 / 64), uint32(100)));
  234. if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.18.00.00"))
  235. {
  236. // Previously, Pitch/Pan Separation was only half depth (plot twist: it was actually only quarter depth).
  237. // This was corrected in compatible mode in OpenMPT 1.18, and in OpenMPT 1.20 it is corrected in normal mode as well.
  238. ins->nPPS = (ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2;
  239. }
  240. if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.17.03.02"))
  241. {
  242. // IT compatibility 24. Short envelope loops
  243. // Previously, the pitch / filter envelope loop handling was broken, the loop was shortened by a tick (like in XM).
  244. // This was corrected in compatible mode in OpenMPT 1.17.03.02, and in OpenMPT 1.20 it is corrected in normal mode as well.
  245. ins->GetEnvelope(ENV_PITCH).Convert(MOD_TYPE_XM, GetType());
  246. }
  247. if(m_dwLastSavedWithVersion >= MPT_V("1.17.00.00") && m_dwLastSavedWithVersion < MPT_V("1.17.02.50"))
  248. {
  249. // If there are any plugins that can receive volume commands, enable volume bug emulation.
  250. if(ins->nMixPlug && ins->HasValidMIDIChannel())
  251. {
  252. m_playBehaviour.set(kMIDICCBugEmulation);
  253. }
  254. }
  255. if(m_dwLastSavedWithVersion < MPT_V("1.17.02.50") && (ins->nVolSwing | ins->nPanSwing | ins->nCutSwing | ins->nResSwing))
  256. {
  257. // If there are any instruments with random variation, enable the old random variation behaviour.
  258. m_playBehaviour.set(kMPTOldSwingBehaviour);
  259. break;
  260. }
  261. }
  262. if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (m_dwLastSavedWithVersion < MPT_V("1.17.03.02") || !compatModeIT))
  263. {
  264. // In the IT format, a sweep value of 0 shouldn't apply vibrato at all. Previously, a value of 0 was treated as "no sweep".
  265. // In OpenMPT 1.17.03.02, this was corrected in compatible mode, in OpenMPT 1.20 it is corrected in normal mode as well,
  266. // so we have to fix the setting while loading.
  267. for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
  268. {
  269. if(Samples[i].nVibSweep == 0 && (Samples[i].nVibDepth | Samples[i].nVibRate))
  270. {
  271. Samples[i].nVibSweep = 255;
  272. }
  273. }
  274. }
  275. // Fix old nasty broken (non-standard) MIDI configs in files.
  276. m_MidiCfg.UpgradeMacros();
  277. }
  278. if(m_dwLastSavedWithVersion < MPT_V("1.20.02.10")
  279. && m_dwLastSavedWithVersion != MPT_V("1.20.00.00")
  280. && (GetType() & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT)))
  281. {
  282. bool instrPlugs = false;
  283. // Old pitch wheel commands were closest to sample pitch bend commands if the PWD is 13.
  284. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
  285. {
  286. if(Instruments[i] != nullptr && Instruments[i]->nMidiChannel != MidiNoChannel)
  287. {
  288. Instruments[i]->midiPWD = 13;
  289. instrPlugs = true;
  290. }
  291. }
  292. if(instrPlugs)
  293. {
  294. m_playBehaviour.set(kOldMIDIPitchBends);
  295. }
  296. }
  297. if(m_dwLastSavedWithVersion < MPT_V("1.22.03.12")
  298. && m_dwLastSavedWithVersion != MPT_V("1.22.00.00")
  299. && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
  300. && (m_playBehaviour[MSF_COMPATIBLE_PLAY] || m_playBehaviour[kMPTOldSwingBehaviour]))
  301. {
  302. // The "correct" pan swing implementation did nothing if the instrument also had a pan envelope.
  303. // If there's a pan envelope, disable pan swing for such modules.
  304. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
  305. {
  306. if(Instruments[i] != nullptr && Instruments[i]->nPanSwing != 0 && Instruments[i]->PanEnv.dwFlags[ENV_ENABLED])
  307. {
  308. Instruments[i]->nPanSwing = 0;
  309. }
  310. }
  311. }
  312. #ifndef NO_PLUGINS
  313. if(m_dwLastSavedWithVersion < MPT_V("1.22.07.01"))
  314. {
  315. // Convert ANSI plugin path names to UTF-8 (irrelevant in probably 99% of all cases anyway, I think I've never seen a VST plugin with a non-ASCII file name)
  316. for(auto &plugin : m_MixPlugins)
  317. {
  318. #if defined(MODPLUG_TRACKER)
  319. const std::string name = mpt::ToCharset(mpt::Charset::UTF8, mpt::Charset::Locale, plugin.Info.szLibraryName);
  320. #else
  321. const std::string name = mpt::ToCharset(mpt::Charset::UTF8, mpt::Charset::Windows1252, plugin.Info.szLibraryName);
  322. #endif
  323. plugin.Info.szLibraryName = name;
  324. }
  325. }
  326. #endif // NO_PLUGINS
  327. // Starting from OpenMPT 1.22.07.19, FT2-style panning was applied in compatible mix mode.
  328. // Starting from OpenMPT 1.23.01.04, FT2-style panning has its own mix mode instead.
  329. if(GetType() == MOD_TYPE_XM)
  330. {
  331. if(m_dwLastSavedWithVersion >= MPT_V("1.22.07.19")
  332. && m_dwLastSavedWithVersion < MPT_V("1.23.01.04")
  333. && GetMixLevels() == MixLevels::Compatible)
  334. {
  335. SetMixLevels(MixLevels::CompatibleFT2);
  336. }
  337. }
  338. if(m_dwLastSavedWithVersion < MPT_V("1.25.00.07") && m_dwLastSavedWithVersion != MPT_V("1.25.00.00"))
  339. {
  340. // Instrument plugins can now receive random volume variation.
  341. // For old instruments, disable volume swing in case there was no sample associated.
  342. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
  343. {
  344. if(Instruments[i] != nullptr && Instruments[i]->nVolSwing != 0 && Instruments[i]->nMidiChannel != MidiNoChannel)
  345. {
  346. bool hasSample = false;
  347. for(auto smp : Instruments[i]->Keyboard)
  348. {
  349. if(smp != 0)
  350. {
  351. hasSample = true;
  352. break;
  353. }
  354. }
  355. if(!hasSample)
  356. {
  357. Instruments[i]->nVolSwing = 0;
  358. }
  359. }
  360. }
  361. }
  362. if(m_dwLastSavedWithVersion < MPT_V("1.26.00.00"))
  363. {
  364. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
  365. {
  366. ModInstrument *ins = Instruments[i];
  367. // Even after fixing it in OpenMPT 1.18, instrument PPS was only half the depth.
  368. ins->nPPS = (ins->nPPS + (ins->nPPS >= 0 ? 1 : -1)) / 2;
  369. // OpenMPT 1.18 fixed the depth of random pan in compatible mode.
  370. // OpenMPT 1.26 fixes it in normal mode too.
  371. if(!compatModeIT || m_dwLastSavedWithVersion < MPT_V("1.18.00.00"))
  372. {
  373. ins->nPanSwing = (ins->nPanSwing + 3) / 4u;
  374. }
  375. }
  376. }
  377. if(m_dwLastSavedWithVersion < MPT_V("1.28.00.12"))
  378. {
  379. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
  380. {
  381. if(Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET)
  382. {
  383. m_playBehaviour.set(kLegacyReleaseNode);
  384. break;
  385. }
  386. }
  387. }
  388. if(m_dwLastSavedWithVersion < MPT_V("1.28.03.04"))
  389. {
  390. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if (Instruments[i] != nullptr)
  391. {
  392. if(Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_MIDI || Instruments[i]->pluginVolumeHandling == PLUGIN_VOLUMEHANDLING_DRYWET)
  393. {
  394. m_playBehaviour.set(kMIDIVolumeOnNoteOffBug);
  395. break;
  396. }
  397. }
  398. }
  399. if(m_dwLastSavedWithVersion < MPT_V("1.30.00.54"))
  400. {
  401. for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
  402. {
  403. if(Samples[i].HasSampleData() && Samples[i].uFlags[CHN_PINGPONGLOOP | CHN_PINGPONGSUSTAIN])
  404. {
  405. m_playBehaviour.set(kImprecisePingPongLoops);
  406. break;
  407. }
  408. }
  409. }
  410. Patterns.ForEachModCommand(UpgradePatternData(*this));
  411. // Convert compatibility flags
  412. // NOTE: Some of these version numbers are just approximations.
  413. // Sometimes a quirk flag is shared by several code locations which might have been fixed at different times.
  414. // Sometimes the quirk behaviour has been revised over time, in which case the first version that emulated the quirk enables it.
  415. struct PlayBehaviourVersion
  416. {
  417. PlayBehaviour behaviour;
  418. Version version;
  419. };
  420. if(compatModeIT && m_dwLastSavedWithVersion < MPT_V("1.26.00.00"))
  421. {
  422. // Pre-1.26: Detailed compatibility flags did not exist.
  423. static constexpr PlayBehaviourVersion behaviours[] =
  424. {
  425. { kTempoClamp, MPT_V("1.17.03.02") },
  426. { kPerChannelGlobalVolSlide, MPT_V("1.17.03.02") },
  427. { kPanOverride, MPT_V("1.17.03.02") },
  428. { kITInstrWithoutNote, MPT_V("1.17.02.46") },
  429. { kITVolColFinePortamento, MPT_V("1.17.02.49") },
  430. { kITArpeggio, MPT_V("1.17.02.49") },
  431. { kITOutOfRangeDelay, MPT_V("1.17.02.49") },
  432. { kITPortaMemoryShare, MPT_V("1.17.02.49") },
  433. { kITPatternLoopTargetReset, MPT_V("1.17.02.49") },
  434. { kITFT2PatternLoop, MPT_V("1.17.02.49") },
  435. { kITPingPongNoReset, MPT_V("1.17.02.51") },
  436. { kITEnvelopeReset, MPT_V("1.17.02.51") },
  437. { kITClearOldNoteAfterCut, MPT_V("1.17.02.52") },
  438. { kITVibratoTremoloPanbrello, MPT_V("1.17.03.02") },
  439. { kITTremor, MPT_V("1.17.03.02") },
  440. { kITRetrigger, MPT_V("1.17.03.02") },
  441. { kITMultiSampleBehaviour, MPT_V("1.17.03.02") },
  442. { kITPortaTargetReached, MPT_V("1.17.03.02") },
  443. { kITPatternLoopBreak, MPT_V("1.17.03.02") },
  444. { kITOffset, MPT_V("1.17.03.02") },
  445. { kITSwingBehaviour, MPT_V("1.18.00.00") },
  446. { kITNNAReset, MPT_V("1.18.00.00") },
  447. { kITSCxStopsSample, MPT_V("1.18.00.01") },
  448. { kITEnvelopePositionHandling, MPT_V("1.18.01.00") },
  449. { kITPortamentoInstrument, MPT_V("1.19.00.01") },
  450. { kITPingPongMode, MPT_V("1.19.00.21") },
  451. { kITRealNoteMapping, MPT_V("1.19.00.30") },
  452. { kITHighOffsetNoRetrig, MPT_V("1.20.00.14") },
  453. { kITFilterBehaviour, MPT_V("1.20.00.35") },
  454. { kITNoSurroundPan, MPT_V("1.20.00.53") },
  455. { kITShortSampleRetrig, MPT_V("1.20.00.54") },
  456. { kITPortaNoNote, MPT_V("1.20.00.56") },
  457. { kRowDelayWithNoteDelay, MPT_V("1.20.00.76") },
  458. { kITFT2DontResetNoteOffOnPorta, MPT_V("1.20.02.06") },
  459. { kITVolColMemory, MPT_V("1.21.01.16") },
  460. { kITPortamentoSwapResetsPos, MPT_V("1.21.01.25") },
  461. { kITEmptyNoteMapSlot, MPT_V("1.21.01.25") },
  462. { kITFirstTickHandling, MPT_V("1.22.07.09") },
  463. { kITSampleAndHoldPanbrello, MPT_V("1.22.07.19") },
  464. { kITClearPortaTarget, MPT_V("1.23.04.03") },
  465. { kITPanbrelloHold, MPT_V("1.24.01.06") },
  466. { kITPanningReset, MPT_V("1.24.01.06") },
  467. { kITPatternLoopWithJumpsOld, MPT_V("1.25.00.19") },
  468. };
  469. for(const auto &b : behaviours)
  470. {
  471. m_playBehaviour.set(b.behaviour, (m_dwLastSavedWithVersion >= b.version || m_dwLastSavedWithVersion == b.version.Masked(0xFFFF0000u)));
  472. }
  473. } else if(compatModeXM && m_dwLastSavedWithVersion < MPT_V("1.26.00.00"))
  474. {
  475. // Pre-1.26: Detailed compatibility flags did not exist.
  476. static constexpr PlayBehaviourVersion behaviours[] =
  477. {
  478. { kTempoClamp, MPT_V("1.17.03.02") },
  479. { kPerChannelGlobalVolSlide, MPT_V("1.17.03.02") },
  480. { kPanOverride, MPT_V("1.17.03.02") },
  481. { kITFT2PatternLoop, MPT_V("1.17.03.02") },
  482. { kFT2Arpeggio, MPT_V("1.17.03.02") },
  483. { kFT2Retrigger, MPT_V("1.17.03.02") },
  484. { kFT2VolColVibrato, MPT_V("1.17.03.02") },
  485. { kFT2PortaNoNote, MPT_V("1.17.03.02") },
  486. { kFT2KeyOff, MPT_V("1.17.03.02") },
  487. { kFT2PanSlide, MPT_V("1.17.03.02") },
  488. { kFT2ST3OffsetOutOfRange, MPT_V("1.17.03.02") },
  489. { kFT2RestrictXCommand, MPT_V("1.18.00.00") },
  490. { kFT2RetrigWithNoteDelay, MPT_V("1.18.00.00") },
  491. { kFT2SetPanEnvPos, MPT_V("1.18.00.00") },
  492. { kFT2PortaIgnoreInstr, MPT_V("1.18.00.01") },
  493. { kFT2VolColMemory, MPT_V("1.18.01.00") },
  494. { kFT2LoopE60Restart, MPT_V("1.18.02.01") },
  495. { kFT2ProcessSilentChannels, MPT_V("1.18.02.01") },
  496. { kFT2ReloadSampleSettings, MPT_V("1.20.00.36") },
  497. { kFT2PortaDelay, MPT_V("1.20.00.40") },
  498. { kFT2Transpose, MPT_V("1.20.00.62") },
  499. { kFT2PatternLoopWithJumps, MPT_V("1.20.00.69") },
  500. { kFT2PortaTargetNoReset, MPT_V("1.20.00.69") },
  501. { kFT2EnvelopeEscape, MPT_V("1.20.00.77") },
  502. { kFT2Tremor, MPT_V("1.20.01.11") },
  503. { kFT2OutOfRangeDelay, MPT_V("1.20.02.02") },
  504. { kFT2Periods, MPT_V("1.22.03.01") },
  505. { kFT2PanWithDelayedNoteOff, MPT_V("1.22.03.02") },
  506. { kFT2VolColDelay, MPT_V("1.22.07.19") },
  507. { kFT2FinetunePrecision, MPT_V("1.22.07.19") },
  508. };
  509. for(const auto &b : behaviours)
  510. {
  511. m_playBehaviour.set(b.behaviour, m_dwLastSavedWithVersion >= b.version);
  512. }
  513. }
  514. if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
  515. {
  516. // The following behaviours were added in/after OpenMPT 1.26, so are not affected by the upgrade mechanism above.
  517. static constexpr PlayBehaviourVersion behaviours[] =
  518. {
  519. { kITInstrWithNoteOff, MPT_V("1.26.00.01") },
  520. { kITMultiSampleInstrumentNumber, MPT_V("1.27.00.27") },
  521. { kITInstrWithNoteOffOldEffects, MPT_V("1.28.02.06") },
  522. { kITDoNotOverrideChannelPan, MPT_V("1.29.00.22") },
  523. { kITPatternLoopWithJumps, MPT_V("1.29.00.32") },
  524. { kITDCTBehaviour, MPT_V("1.29.00.57") },
  525. { kITPitchPanSeparation, MPT_V("1.30.00.53") },
  526. };
  527. for(const auto &b : behaviours)
  528. {
  529. if(m_dwLastSavedWithVersion < b.version.Masked(0xFFFF0000u))
  530. m_playBehaviour.reset(b.behaviour);
  531. // Full version information available, i.e. not compatibility-exported.
  532. else if(m_dwLastSavedWithVersion > b.version.Masked(0xFFFF0000u) && m_dwLastSavedWithVersion < b.version)
  533. m_playBehaviour.reset(b.behaviour);
  534. }
  535. } else if(GetType() == MOD_TYPE_XM)
  536. {
  537. // The following behaviours were added after OpenMPT 1.26, so are not affected by the upgrade mechanism above.
  538. static constexpr PlayBehaviourVersion behaviours[] =
  539. {
  540. { kFT2NoteOffFlags, MPT_V("1.27.00.27") },
  541. { kRowDelayWithNoteDelay, MPT_V("1.27.00.37") },
  542. { kFT2MODTremoloRampWaveform, MPT_V("1.27.00.37") },
  543. { kFT2PortaUpDownMemory, MPT_V("1.27.00.37") },
  544. { kFT2PanSustainRelease, MPT_V("1.28.00.09") },
  545. { kFT2NoteDelayWithoutInstr, MPT_V("1.28.00.44") },
  546. { kITFT2DontResetNoteOffOnPorta, MPT_V("1.29.00.34") },
  547. { kFT2PortaResetDirection, MPT_V("1.30.00.40") },
  548. };
  549. for(const auto &b : behaviours)
  550. {
  551. if(m_dwLastSavedWithVersion < b.version)
  552. m_playBehaviour.reset(b.behaviour);
  553. }
  554. } else if(GetType() == MOD_TYPE_S3M)
  555. {
  556. // We do not store any of these flags in S3M files.
  557. static constexpr PlayBehaviourVersion behaviours[] =
  558. {
  559. { kST3NoMutedChannels, MPT_V("1.18.00.00") },
  560. { kST3EffectMemory, MPT_V("1.20.00.00") },
  561. { kRowDelayWithNoteDelay, MPT_V("1.20.00.00") },
  562. { kST3PortaSampleChange, MPT_V("1.22.00.00") },
  563. { kST3VibratoMemory, MPT_V("1.26.00.00") },
  564. { kITPanbrelloHold, MPT_V("1.26.00.00") },
  565. { KST3PortaAfterArpeggio, MPT_V("1.27.00.00") },
  566. { kST3OffsetWithoutInstrument, MPT_V("1.28.00.00") },
  567. { kST3RetrigAfterNoteCut, MPT_V("1.29.00.00") },
  568. { kFT2ST3OffsetOutOfRange, MPT_V("1.29.00.00") },
  569. { kApplyUpperPeriodLimit, MPT_V("1.30.00.45") },
  570. };
  571. for(const auto &b : behaviours)
  572. {
  573. if(m_dwLastSavedWithVersion < b.version)
  574. m_playBehaviour.reset(b.behaviour);
  575. }
  576. }
  577. if(GetType() == MOD_TYPE_XM && m_dwLastSavedWithVersion < MPT_V("1.19.00.00"))
  578. {
  579. // This bug was introduced sometime between 1.18.03.00 and 1.19.01.00
  580. m_playBehaviour.set(kFT2NoteDelayWithoutInstr);
  581. }
  582. if(m_dwLastSavedWithVersion >= MPT_V("1.27.00.27") && m_dwLastSavedWithVersion < MPT_V("1.27.00.49"))
  583. {
  584. // OpenMPT 1.27 inserted some IT/FT2 flags before the S3M flags that are never saved to files anyway, to keep the flag IDs a bit more compact.
  585. // However, it was overlooked that these flags would still be read by OpenMPT 1.26 and thus S3M-specific behaviour would be enabled in IT/XM files.
  586. // Hence, in OpenMPT 1.27.00.49 the flag IDs got remapped to no longer conflict with OpenMPT 1.26.
  587. // Files made with the affected pre-release versions of OpenMPT 1.27 are upgraded here to use the new IDs.
  588. for(int i = 0; i < 5; i++)
  589. {
  590. m_playBehaviour.set(kFT2NoteOffFlags + i, m_playBehaviour[kST3NoMutedChannels + i]);
  591. m_playBehaviour.reset(kST3NoMutedChannels + i);
  592. }
  593. }
  594. if(m_dwLastSavedWithVersion < MPT_V("1.17.00.00"))
  595. {
  596. // MPT 1.16 has a maximum tempo of 255.
  597. m_playBehaviour.set(kTempoClamp);
  598. } else if(m_dwLastSavedWithVersion >= MPT_V("1.17.00.00") && m_dwLastSavedWithVersion <= MPT_V("1.20.01.03") && m_dwLastSavedWithVersion != MPT_V("1.20.00.00"))
  599. {
  600. // OpenMPT introduced some "fixes" that execute regular portamentos also at speed 1.
  601. m_playBehaviour.set(kSlidesAtSpeed1);
  602. }
  603. if(m_SongFlags[SONG_LINEARSLIDES])
  604. {
  605. if(m_dwLastSavedWithVersion < MPT_V("1.24.00.00"))
  606. {
  607. // No frequency slides in Hz before OpenMPT 1.24
  608. m_playBehaviour.reset(kPeriodsAreHertz);
  609. } else if(m_dwLastSavedWithVersion >= MPT_V("1.24.00.00") && m_dwLastSavedWithVersion < MPT_V("1.26.00.00") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)))
  610. {
  611. // Frequency slides were always in Hz rather than periods in this version range.
  612. m_playBehaviour.set(kPeriodsAreHertz);
  613. }
  614. } else
  615. {
  616. if(m_dwLastSavedWithVersion < MPT_V("1.30.00.36") && m_dwLastSavedWithVersion != MPT_V("1.30.00.00"))
  617. {
  618. // No frequency slides in Hz before OpenMPT 1.30
  619. m_playBehaviour.reset(kPeriodsAreHertz);
  620. }
  621. }
  622. if(m_playBehaviour[kITEnvelopePositionHandling]
  623. && m_dwLastSavedWithVersion >= MPT_V("1.23.01.02") && m_dwLastSavedWithVersion < MPT_V("1.28.00.43"))
  624. {
  625. // Bug that effectively clamped the release node to the sustain end
  626. for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++) if(Instruments[i] != nullptr)
  627. {
  628. if(Instruments[i]->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET
  629. && Instruments[i]->VolEnv.dwFlags[ENV_SUSTAIN]
  630. && Instruments[i]->VolEnv.nReleaseNode > Instruments[i]->VolEnv.nSustainEnd)
  631. {
  632. m_playBehaviour.set(kReleaseNodePastSustainBug);
  633. break;
  634. }
  635. }
  636. }
  637. if(GetType() & (MOD_TYPE_MPT | MOD_TYPE_S3M))
  638. {
  639. for(SAMPLEINDEX i = 1; i <= GetNumSamples(); i++)
  640. {
  641. if(Samples[i].uFlags[CHN_ADLIB])
  642. {
  643. if(GetType() == MOD_TYPE_MPT && GetNumInstruments() && m_dwLastSavedWithVersion >= MPT_V("1.28.00.20") && m_dwLastSavedWithVersion <= MPT_V("1.29.00.55"))
  644. m_playBehaviour.set(kOPLNoResetAtEnvelopeEnd);
  645. if(m_dwLastSavedWithVersion <= MPT_V("1.30.00.34") && m_dwLastSavedWithVersion != MPT_V("1.30"))
  646. m_playBehaviour.reset(kOPLNoteOffOnNoteChange);
  647. if(GetType() == MOD_TYPE_S3M && m_dwLastSavedWithVersion < MPT_V("1.29"))
  648. m_playBehaviour.set(kOPLRealRetrig);
  649. else if(GetType() != MOD_TYPE_S3M)
  650. m_playBehaviour.reset(kOPLRealRetrig);
  651. break;
  652. }
  653. }
  654. }
  655. if(m_dwLastSavedWithVersion >= MPT_V("1.27.00.42") && m_dwLastSavedWithVersion < MPT_V("1.30.00.46") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)))
  656. {
  657. // The Flanger DMO plugin is almost identical to the Chorus... but only almost.
  658. // The effect implementation was the same in OpenMPT 1.27-1.29, now it isn't anymore.
  659. // As the old implementation continues to exist for the Chorus plugin, there is a legacy wrapper for the Flanger plugin.
  660. for(auto &plugin : m_MixPlugins)
  661. {
  662. if(plugin.Info.dwPluginId1 == kDmoMagic && plugin.Info.dwPluginId2 == int32(0xEFCA3D92) && plugin.pluginData.size() == 32)
  663. plugin.Info.szLibraryName = "Flanger (Legacy)";
  664. }
  665. }
  666. if(m_dwLastSavedWithVersion >= MPT_V("1.27") && m_dwLastSavedWithVersion < MPT_V("1.30.06.00") && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM)))
  667. {
  668. // Fix off-by-one delay length in older Echo DMO emulation
  669. for(auto &plugin : m_MixPlugins)
  670. {
  671. if(plugin.Info.dwPluginId1 == kDmoMagic && plugin.Info.dwPluginId2 == int32(0xEF3E932C) && plugin.pluginData.size() == 24)
  672. {
  673. float32le leftDelay, rightDelay;
  674. memcpy(&leftDelay, plugin.pluginData.data() + 12, 4);
  675. memcpy(&rightDelay, plugin.pluginData.data() + 16, 4);
  676. leftDelay = float32le{mpt::safe_clamp(((leftDelay * 2000.0f) - 1.0f) / 1999.0f, 0.0f, 1.0f)};
  677. rightDelay = float32le{mpt::safe_clamp(((rightDelay * 2000.0f) - 1.0f) / 1999.0f, 0.0f, 1.0f)};
  678. memcpy(plugin.pluginData.data() + 12, &leftDelay, 4);
  679. memcpy(plugin.pluginData.data() + 16, &rightDelay, 4);
  680. }
  681. }
  682. }
  683. }
  684. OPENMPT_NAMESPACE_END