1
0

Load_it.cpp 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531
  1. /*
  2. * Load_it.cpp
  3. * -----------
  4. * Purpose: IT (Impulse Tracker) module loader / saver
  5. * Notes : Also handles MPTM loading / saving, as the formats are almost identical.
  6. * Authors: Olivier Lapicque
  7. * 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 "Loaders.h"
  12. #include "tuningcollection.h"
  13. #include "mod_specifications.h"
  14. #ifdef MODPLUG_TRACKER
  15. #include "../mptrack/Moddoc.h"
  16. #include "../mptrack/TrackerSettings.h"
  17. #endif // MODPLUG_TRACKER
  18. #ifdef MPT_EXTERNAL_SAMPLES
  19. #include "../common/mptPathString.h"
  20. #endif // MPT_EXTERNAL_SAMPLES
  21. #include "../common/serialization_utils.h"
  22. #ifndef MODPLUG_NO_FILESAVE
  23. #include "../common/mptFileIO.h"
  24. #endif // MODPLUG_NO_FILESAVE
  25. #include "plugins/PlugInterface.h"
  26. #include <sstream>
  27. #include "../common/version.h"
  28. #include "ITTools.h"
  29. #include "mpt/io/base.hpp"
  30. #include "mpt/io/io.hpp"
  31. #include "mpt/io/io_stdstream.hpp"
  32. OPENMPT_NAMESPACE_BEGIN
  33. const uint16 verMptFileVer = 0x891;
  34. const uint16 verMptFileVerLoadLimit = 0x1000; // If cwtv-field is greater or equal to this value,
  35. // the MPTM file will not be loaded.
  36. /*
  37. MPTM version history for cwtv-field in "IT" header (only for MPTM files!):
  38. 0x890(1.18.02.00) -> 0x891(1.19.00.00): Pattern-specific time signatures
  39. Fixed behaviour of Pattern Loop command for rows > 255 (r617)
  40. 0x88F(1.18.01.00) -> 0x890(1.18.02.00): Removed volume command velocity :xy, added delay-cut command :xy.
  41. 0x88E(1.17.02.50) -> 0x88F(1.18.01.00): Numerous changes
  42. 0x88D(1.17.02.49) -> 0x88E(1.17.02.50): Changed ID to that of IT and undone the orderlist change done in
  43. 0x88A->0x88B. Now extended orderlist is saved as extension.
  44. 0x88C(1.17.02.48) -> 0x88D(1.17.02.49): Some tuning related changes - that part fails to read on older versions.
  45. 0x88B -> 0x88C: Changed type in which tuning number is printed to file: size_t -> uint16.
  46. 0x88A -> 0x88B: Changed order-to-pattern-index table type from uint8-array to vector<uint32>.
  47. */
  48. #ifndef MODPLUG_NO_FILESAVE
  49. static bool AreNonDefaultTuningsUsed(const CSoundFile& sf)
  50. {
  51. const INSTRUMENTINDEX numIns = sf.GetNumInstruments();
  52. for(INSTRUMENTINDEX i = 1; i <= numIns; i++)
  53. {
  54. if(sf.Instruments[i] != nullptr && sf.Instruments[i]->pTuning != nullptr)
  55. return true;
  56. }
  57. return false;
  58. }
  59. static void WriteTuningCollection(std::ostream& oStrm, const CTuningCollection& tc)
  60. {
  61. tc.Serialize(oStrm, U_("Tune specific tunings"));
  62. }
  63. static void WriteTuningMap(std::ostream& oStrm, const CSoundFile& sf)
  64. {
  65. if(sf.GetNumInstruments() > 0)
  66. {
  67. //Writing instrument tuning data: first creating
  68. //tuning name <-> tuning id number map,
  69. //and then writing the tuning id for every instrument.
  70. //For example if there are 6 instruments and
  71. //first half use tuning 'T1', and the other half
  72. //tuning 'T2', the output would be something like
  73. //T1 1 T2 2 1 1 1 2 2 2
  74. //Creating the tuning address <-> tuning id number map.
  75. std::map<CTuning*, uint16> tNameToShort_Map;
  76. unsigned short figMap = 0;
  77. for(INSTRUMENTINDEX i = 1; i <= sf.GetNumInstruments(); i++)
  78. {
  79. CTuning *pTuning = nullptr;
  80. if(sf.Instruments[i] != nullptr)
  81. {
  82. pTuning = sf.Instruments[i]->pTuning;
  83. }
  84. auto iter = tNameToShort_Map.find(pTuning);
  85. if(iter != tNameToShort_Map.end())
  86. continue; //Tuning already mapped.
  87. tNameToShort_Map[pTuning] = figMap;
  88. figMap++;
  89. }
  90. //...and write the map with tuning names replacing
  91. //the addresses.
  92. const uint16 tuningMapSize = static_cast<uint16>(tNameToShort_Map.size());
  93. mpt::IO::WriteIntLE<uint16>(oStrm, tuningMapSize);
  94. for(auto &iter : tNameToShort_Map)
  95. {
  96. if(iter.first)
  97. mpt::IO::WriteSizedStringLE<uint8>(oStrm, mpt::ToCharset(mpt::Charset::UTF8, iter.first->GetName()));
  98. else //Case: Using original IT tuning.
  99. mpt::IO::WriteSizedStringLE<uint8>(oStrm, "->MPT_ORIGINAL_IT<-");
  100. mpt::IO::WriteIntLE<uint16>(oStrm, iter.second);
  101. }
  102. //Writing tuning data for instruments.
  103. for(INSTRUMENTINDEX i = 1; i <= sf.GetNumInstruments(); i++)
  104. {
  105. CTuning *pTuning = nullptr;
  106. if(sf.Instruments[i] != nullptr)
  107. {
  108. pTuning = sf.Instruments[i]->pTuning;
  109. }
  110. auto iter = tNameToShort_Map.find(pTuning);
  111. if(iter == tNameToShort_Map.end()) //Should never happen
  112. {
  113. sf.AddToLog(LogError, U_("Error: 210807_1"));
  114. return;
  115. }
  116. mpt::IO::WriteIntLE<uint16>(oStrm, iter->second);
  117. }
  118. }
  119. }
  120. #endif // MODPLUG_NO_FILESAVE
  121. static void ReadTuningCollection(std::istream &iStrm, CTuningCollection &tc, const std::size_t dummy, mpt::Charset defaultCharset)
  122. {
  123. MPT_UNREFERENCED_PARAMETER(dummy);
  124. mpt::ustring name;
  125. tc.Deserialize(iStrm, name, defaultCharset);
  126. }
  127. template<class TUNNUMTYPE, class STRSIZETYPE>
  128. static bool ReadTuningMapTemplate(std::istream& iStrm, std::map<uint16, mpt::ustring> &shortToTNameMap, mpt::Charset charset, const size_t maxNum = 500)
  129. {
  130. TUNNUMTYPE numTuning = 0;
  131. mpt::IO::ReadIntLE<TUNNUMTYPE>(iStrm, numTuning);
  132. if(numTuning > maxNum)
  133. return true;
  134. for(size_t i = 0; i < numTuning; i++)
  135. {
  136. std::string temp;
  137. uint16 ui = 0;
  138. if(!mpt::IO::ReadSizedStringLE<STRSIZETYPE>(iStrm, temp, 255))
  139. return true;
  140. mpt::IO::ReadIntLE<uint16>(iStrm, ui);
  141. shortToTNameMap[ui] = mpt::ToUnicode(charset, temp);
  142. }
  143. if(iStrm.good())
  144. return false;
  145. else
  146. return true;
  147. }
  148. static void ReadTuningMapImpl(std::istream& iStrm, CSoundFile& csf, mpt::Charset charset, const size_t = 0, bool old = false)
  149. {
  150. std::map<uint16, mpt::ustring> shortToTNameMap;
  151. if(old)
  152. {
  153. ReadTuningMapTemplate<uint32, uint32>(iStrm, shortToTNameMap, charset);
  154. } else
  155. {
  156. ReadTuningMapTemplate<uint16, uint8>(iStrm, shortToTNameMap, charset);
  157. }
  158. // Read & set tunings for instruments
  159. std::vector<mpt::ustring> notFoundTunings;
  160. for(INSTRUMENTINDEX i = 1; i<=csf.GetNumInstruments(); i++)
  161. {
  162. uint16 ui = 0;
  163. mpt::IO::ReadIntLE<uint16>(iStrm, ui);
  164. auto iter = shortToTNameMap.find(ui);
  165. if(csf.Instruments[i] && iter != shortToTNameMap.end())
  166. {
  167. const mpt::ustring str = iter->second;
  168. if(str == U_("->MPT_ORIGINAL_IT<-"))
  169. {
  170. csf.Instruments[i]->pTuning = nullptr;
  171. continue;
  172. }
  173. csf.Instruments[i]->pTuning = csf.GetTuneSpecificTunings().GetTuning(str);
  174. if(csf.Instruments[i]->pTuning)
  175. continue;
  176. #ifdef MODPLUG_TRACKER
  177. CTuning *localTuning = TrackerSettings::Instance().oldLocalTunings->GetTuning(str);
  178. if(localTuning)
  179. {
  180. std::unique_ptr<CTuning> pNewTuning = std::unique_ptr<CTuning>(new CTuning(*localTuning));
  181. CTuning *pT = csf.GetTuneSpecificTunings().AddTuning(std::move(pNewTuning));
  182. if(pT)
  183. {
  184. csf.AddToLog(LogInformation, U_("Local tunings are deprecated and no longer supported. Tuning '") + str + U_("' found in Local tunings has been copied to Tune-specific tunings and will be saved in the module file."));
  185. csf.Instruments[i]->pTuning = pT;
  186. if(csf.GetpModDoc() != nullptr)
  187. {
  188. csf.GetpModDoc()->SetModified();
  189. }
  190. continue;
  191. } else
  192. {
  193. csf.AddToLog(LogError, U_("Copying Local tuning '") + str + U_("' to Tune-specific tunings failed."));
  194. }
  195. }
  196. #endif
  197. if(str == U_("12TET [[fs15 1.17.02.49]]") || str == U_("12TET"))
  198. {
  199. std::unique_ptr<CTuning> pNewTuning = csf.CreateTuning12TET(str);
  200. CTuning *pT = csf.GetTuneSpecificTunings().AddTuning(std::move(pNewTuning));
  201. if(pT)
  202. {
  203. #ifdef MODPLUG_TRACKER
  204. csf.AddToLog(LogInformation, U_("Built-in tunings will no longer be used. Tuning '") + str + U_("' has been copied to Tune-specific tunings and will be saved in the module file."));
  205. csf.Instruments[i]->pTuning = pT;
  206. if(csf.GetpModDoc() != nullptr)
  207. {
  208. csf.GetpModDoc()->SetModified();
  209. }
  210. #endif
  211. continue;
  212. } else
  213. {
  214. #ifdef MODPLUG_TRACKER
  215. csf.AddToLog(LogError, U_("Copying Built-in tuning '") + str + U_("' to Tune-specific tunings failed."));
  216. #endif
  217. }
  218. }
  219. // Checking if not found tuning already noticed.
  220. if(!mpt::contains(notFoundTunings, str))
  221. {
  222. notFoundTunings.push_back(str);
  223. csf.AddToLog(LogWarning, U_("Tuning '") + str + U_("' used by the module was not found."));
  224. #ifdef MODPLUG_TRACKER
  225. if(csf.GetpModDoc() != nullptr)
  226. {
  227. csf.GetpModDoc()->SetModified(); // The tuning is changed so the modified flag is set.
  228. }
  229. #endif // MODPLUG_TRACKER
  230. }
  231. csf.Instruments[i]->pTuning = csf.GetDefaultTuning();
  232. } else
  233. {
  234. //This 'else' happens probably only in case of corrupted file.
  235. if(csf.Instruments[i])
  236. csf.Instruments[i]->pTuning = csf.GetDefaultTuning();
  237. }
  238. }
  239. //End read&set instrument tunings
  240. }
  241. static void ReadTuningMap(std::istream& iStrm, CSoundFile& csf, const size_t dummy, mpt::Charset charset)
  242. {
  243. ReadTuningMapImpl(iStrm, csf, charset, dummy, false);
  244. }
  245. //////////////////////////////////////////////////////////
  246. // Impulse Tracker IT file support
  247. size_t CSoundFile::ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers)
  248. {
  249. if(trkvers < 0x0200)
  250. {
  251. // Load old format (IT 1.xx) instrument (early IT 2.xx modules may have cmwt set to 1.00 for backwards compatibility)
  252. ITOldInstrument instrumentHeader;
  253. if(!file.ReadStruct(instrumentHeader))
  254. {
  255. return 0;
  256. } else
  257. {
  258. instrumentHeader.ConvertToMPT(ins);
  259. return sizeof(ITOldInstrument);
  260. }
  261. } else
  262. {
  263. const FileReader::off_t offset = file.GetPosition();
  264. // Try loading extended instrument... instSize will differ between normal and extended instruments.
  265. ITInstrumentEx instrumentHeader;
  266. file.ReadStructPartial(instrumentHeader);
  267. size_t instSize = instrumentHeader.ConvertToMPT(ins, GetType());
  268. file.Seek(offset + instSize);
  269. // Try reading modular instrument data.
  270. // Yes, it is completely idiotic that we have both this and LoadExtendedInstrumentProperties.
  271. // This is only required for files saved with *really* old OpenMPT versions (pre-1.17-RC1).
  272. // This chunk was also written in later versions (probably to maintain compatibility with
  273. // those ancient versions), but this also means that redundant information is stored in the file.
  274. // Starting from OpenMPT 1.25.02.07, this chunk is no longer written.
  275. if(file.ReadMagic("MSNI"))
  276. {
  277. //...the next piece of data must be the total size of the modular data
  278. FileReader modularData = file.ReadChunk(file.ReadUint32LE());
  279. instSize += 8 + modularData.GetLength();
  280. if(modularData.ReadMagic("GULP"))
  281. {
  282. ins.nMixPlug = modularData.ReadUint8();
  283. if(ins.nMixPlug > MAX_MIXPLUGINS) ins.nMixPlug = 0;
  284. }
  285. }
  286. return instSize;
  287. }
  288. }
  289. static void CopyPatternName(CPattern &pattern, FileReader &file)
  290. {
  291. char name[MAX_PATTERNNAME] = "";
  292. file.ReadString<mpt::String::maybeNullTerminated>(name, MAX_PATTERNNAME);
  293. pattern.SetName(name);
  294. }
  295. // Get version of Schism Tracker that was used to create an IT/S3M file.
  296. mpt::ustring CSoundFile::GetSchismTrackerVersion(uint16 cwtv, uint32 reserved)
  297. {
  298. // Schism Tracker version information in a nutshell:
  299. // < 0x020: a proper version (files saved by such versions are likely very rare)
  300. // = 0x020: any version between the 0.2a release (2005-04-29?) and 2007-04-17
  301. // = 0x050: anywhere from 2007-04-17 to 2009-10-31
  302. // > 0x050: the number of days since 2009-10-31
  303. // = 0xFFF: any version starting from 2020-10-28 (exact version stored in reserved value)
  304. cwtv &= 0xFFF;
  305. if(cwtv > 0x050)
  306. {
  307. int32 date = SchismTrackerEpoch + (cwtv < 0xFFF ? cwtv - 0x050 : reserved);
  308. int32 y = static_cast<int32>((Util::mul32to64(10000, date) + 14780) / 3652425);
  309. int32 ddd = date - (365 * y + y / 4 - y / 100 + y / 400);
  310. if(ddd < 0)
  311. {
  312. y--;
  313. ddd = date - (365 * y + y / 4 - y / 100 + y / 400);
  314. }
  315. int32 mi = (100 * ddd + 52) / 3060;
  316. return MPT_UFORMAT("Schism Tracker {}-{}-{}")(
  317. mpt::ufmt::dec0<4>(y + (mi + 2) / 12),
  318. mpt::ufmt::dec0<2>((mi + 2) % 12 + 1),
  319. mpt::ufmt::dec0<2>(ddd - (mi * 306 + 5) / 10 + 1));
  320. } else
  321. {
  322. return MPT_UFORMAT("Schism Tracker 0.{}")(mpt::ufmt::hex0<2>(cwtv));
  323. }
  324. }
  325. static bool ValidateHeader(const ITFileHeader &fileHeader)
  326. {
  327. if((std::memcmp(fileHeader.id, "IMPM", 4) && std::memcmp(fileHeader.id, "tpm.", 4))
  328. || fileHeader.insnum > 0xFF
  329. || fileHeader.smpnum >= MAX_SAMPLES
  330. )
  331. {
  332. return false;
  333. }
  334. return true;
  335. }
  336. static uint64 GetHeaderMinimumAdditionalSize(const ITFileHeader &fileHeader)
  337. {
  338. return fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4;
  339. }
  340. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize)
  341. {
  342. ITFileHeader fileHeader;
  343. if(!file.ReadStruct(fileHeader))
  344. {
  345. return ProbeWantMoreData;
  346. }
  347. if(!ValidateHeader(fileHeader))
  348. {
  349. return ProbeFailure;
  350. }
  351. return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
  352. }
  353. bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
  354. {
  355. file.Rewind();
  356. ITFileHeader fileHeader;
  357. if(!file.ReadStruct(fileHeader))
  358. {
  359. return false;
  360. }
  361. if(!ValidateHeader(fileHeader))
  362. {
  363. return false;
  364. }
  365. if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
  366. {
  367. return false;
  368. }
  369. if(loadFlags == onlyVerifyHeader)
  370. {
  371. return true;
  372. }
  373. InitializeGlobals(MOD_TYPE_IT);
  374. bool interpretModPlugMade = false;
  375. mpt::ustring madeWithTracker;
  376. // OpenMPT crap at the end of file
  377. size_t mptStartPos = 0;
  378. if(!memcmp(fileHeader.id, "tpm.", 4))
  379. {
  380. // Legacy MPTM files (old 1.17.02.4x releases)
  381. SetType(MOD_TYPE_MPT);
  382. file.Seek(file.GetLength() - 4);
  383. mptStartPos = file.ReadUint32LE();
  384. } else
  385. {
  386. if(fileHeader.cwtv > 0x888 && fileHeader.cwtv <= 0xFFF)
  387. {
  388. file.Seek(file.GetLength() - 4);
  389. mptStartPos = file.ReadUint32LE();
  390. if(mptStartPos >= 0x100 && mptStartPos < file.GetLength())
  391. {
  392. if(file.Seek(mptStartPos) && file.ReadMagic("228"))
  393. {
  394. SetType(MOD_TYPE_MPT);
  395. if(fileHeader.cwtv >= verMptFileVerLoadLimit)
  396. {
  397. AddToLog(LogError, U_("The file informed that it is incompatible with this version of OpenMPT. Loading was terminated."));
  398. return false;
  399. } else if(fileHeader.cwtv > verMptFileVer)
  400. {
  401. AddToLog(LogInformation, U_("The loaded file was made with a more recent OpenMPT version and this version may not be able to load all the features or play the file correctly."));
  402. }
  403. }
  404. }
  405. }
  406. if(GetType() == MOD_TYPE_IT)
  407. {
  408. // Which tracker was used to make this?
  409. if((fileHeader.cwtv & 0xF000) == 0x5000)
  410. {
  411. // OpenMPT Version number (Major.Minor)
  412. // This will only be interpreted as "made with ModPlug" (i.e. disable compatible playback etc) if the "reserved" field is set to "OMPT" - else, compatibility was used.
  413. uint32 mptVersion = (fileHeader.cwtv & 0x0FFF) << 16;
  414. if(!memcmp(&fileHeader.reserved, "OMPT", 4))
  415. interpretModPlugMade = true;
  416. else if(mptVersion >= 0x01'29'00'00)
  417. mptVersion |= fileHeader.reserved & 0xFFFF;
  418. m_dwLastSavedWithVersion = Version(mptVersion);
  419. } else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888)
  420. {
  421. // OpenMPT 1.17.02.26 (r122) to 1.18 (raped IT format)
  422. // Exact version number will be determined later.
  423. interpretModPlugMade = true;
  424. m_dwLastSavedWithVersion = MPT_V("1.17.00.00");
  425. } else if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0)
  426. {
  427. if(memchr(fileHeader.chnpan, 0xFF, sizeof(fileHeader.chnpan)) != nullptr)
  428. {
  429. // ModPlug Tracker 1.16 (semi-raped IT format) or BeRoTracker (will be determined later)
  430. m_dwLastSavedWithVersion = MPT_V("1.16.00.00");
  431. madeWithTracker = U_("ModPlug Tracker 1.09 - 1.16");
  432. } else
  433. {
  434. // OpenMPT 1.17 disguised as this in compatible mode,
  435. // but never writes 0xFF in the pan map for unused channels (which is an invalid value).
  436. m_dwLastSavedWithVersion = MPT_V("1.17.00.00");
  437. madeWithTracker = U_("OpenMPT 1.17 (compatibility export)");
  438. }
  439. interpretModPlugMade = true;
  440. } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && fileHeader.reserved == 0)
  441. {
  442. // ModPlug Tracker b3.3 - 1.09, instruments 557 bytes apart
  443. m_dwLastSavedWithVersion = MPT_V("1.09.00.00");
  444. madeWithTracker = U_("ModPlug Tracker b3.3 - 1.09");
  445. interpretModPlugMade = true;
  446. } else if(fileHeader.cwtv == 0x0300 && fileHeader.cmwt == 0x0300 && fileHeader.reserved == 0 && fileHeader.ordnum == 256 && fileHeader.sep == 128 && fileHeader.pwd == 0)
  447. {
  448. // A rare variant used from OpenMPT 1.17.02.20 (r113) to 1.17.02.25 (r121), found e.g. in xTr1m-SD.it
  449. m_dwLastSavedWithVersion = MPT_V("1.17.02.20");
  450. interpretModPlugMade = true;
  451. }
  452. }
  453. }
  454. m_SongFlags.set(SONG_LINEARSLIDES, (fileHeader.flags & ITFileHeader::linearSlides) != 0);
  455. m_SongFlags.set(SONG_ITOLDEFFECTS, (fileHeader.flags & ITFileHeader::itOldEffects) != 0);
  456. m_SongFlags.set(SONG_ITCOMPATGXX, (fileHeader.flags & ITFileHeader::itCompatGxx) != 0);
  457. m_SongFlags.set(SONG_EXFILTERRANGE, (fileHeader.flags & ITFileHeader::extendedFilterRange) != 0);
  458. m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songname);
  459. // Read row highlights
  460. if((fileHeader.special & ITFileHeader::embedPatternHighlights))
  461. {
  462. // MPT 1.09 and older (and maybe also newer) versions leave this blank (0/0), but have the "special" flag set.
  463. // Newer versions of MPT and OpenMPT 1.17 *always* write 4/16 here.
  464. // Thus, we will just ignore those old versions.
  465. // Note: OpenMPT 1.17.03.02 was the first version to properly make use of the time signature in the IT header.
  466. // This poses a small unsolvable problem:
  467. // - In compatible mode, we cannot distinguish this version from earlier 1.17 releases.
  468. // Thus we cannot know when to read this field or not (m_dwLastSavedWithVersion will always be 1.17.00.00).
  469. // Luckily OpenMPT 1.17.03.02 should not be very wide-spread.
  470. // - In normal mode the time signature is always present in the song extensions anyway. So it's okay if we read
  471. // the signature here and maybe overwrite it later when parsing the song extensions.
  472. if(!m_dwLastSavedWithVersion || m_dwLastSavedWithVersion >= MPT_V("1.17.03.02"))
  473. {
  474. m_nDefaultRowsPerBeat = fileHeader.highlight_minor;
  475. m_nDefaultRowsPerMeasure = fileHeader.highlight_major;
  476. }
  477. }
  478. // Global Volume
  479. m_nDefaultGlobalVolume = fileHeader.globalvol << 1;
  480. if(m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME)
  481. m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
  482. if(fileHeader.speed)
  483. m_nDefaultSpeed = fileHeader.speed;
  484. m_nDefaultTempo.Set(std::max(uint8(31), static_cast<uint8>(fileHeader.tempo)));
  485. m_nSamplePreAmp = std::min(static_cast<uint8>(fileHeader.mv), uint8(128));
  486. // Reading Channels Pan Positions
  487. for(CHANNELINDEX i = 0; i < 64; i++) if(fileHeader.chnpan[i] != 0xFF)
  488. {
  489. ChnSettings[i].Reset();
  490. ChnSettings[i].nVolume = Clamp<uint8, uint8>(fileHeader.chnvol[i], 0, 64);
  491. if(fileHeader.chnpan[i] & 0x80) ChnSettings[i].dwFlags.set(CHN_MUTE);
  492. uint8 n = fileHeader.chnpan[i] & 0x7F;
  493. if(n <= 64) ChnSettings[i].nPan = n * 4;
  494. if(n == 100) ChnSettings[i].dwFlags.set(CHN_SURROUND);
  495. }
  496. // Reading orders
  497. file.Seek(sizeof(ITFileHeader));
  498. if(GetType() == MOD_TYPE_MPT && fileHeader.cwtv > 0x88A && fileHeader.cwtv <= 0x88D)
  499. {
  500. // Deprecated format used for MPTm files created with OpenMPT 1.17.02.46 - 1.17.02.48.
  501. uint16 version = file.ReadUint16LE();
  502. if(version != 0)
  503. return false;
  504. uint32 numOrd = file.ReadUint32LE();
  505. if(numOrd > ModSpecs::mptm.ordersMax || !ReadOrderFromFile<uint32le>(Order(), file, numOrd))
  506. return false;
  507. } else
  508. {
  509. ReadOrderFromFile<uint8>(Order(), file, fileHeader.ordnum, 0xFF, 0xFE);
  510. }
  511. // Reading instrument, sample and pattern offsets
  512. std::vector<uint32le> insPos, smpPos, patPos;
  513. if(!file.ReadVector(insPos, fileHeader.insnum)
  514. || !file.ReadVector(smpPos, fileHeader.smpnum)
  515. || !file.ReadVector(patPos, fileHeader.patnum))
  516. {
  517. return false;
  518. }
  519. // Find the first parapointer.
  520. // This is used for finding out whether the edit history is actually stored in the file or not,
  521. // as some early versions of Schism Tracker set the history flag, but didn't save anything.
  522. // We will consider the history invalid if it ends after the first parapointer.
  523. uint32 minPtr = std::numeric_limits<decltype(minPtr)>::max();
  524. for(uint32 pos : insPos)
  525. {
  526. if(pos > 0 && pos < minPtr)
  527. minPtr = pos;
  528. }
  529. for(uint32 pos : smpPos)
  530. {
  531. if(pos > 0 && pos < minPtr)
  532. minPtr = pos;
  533. }
  534. for(uint32 pos : patPos)
  535. {
  536. if(pos > 0 && pos < minPtr)
  537. minPtr = pos;
  538. }
  539. if(fileHeader.special & ITFileHeader::embedSongMessage)
  540. {
  541. minPtr = std::min(minPtr, fileHeader.msgoffset.get());
  542. }
  543. const bool possiblyUNMO3 = fileHeader.cmwt == 0x0214 && (fileHeader.cwtv == 0x0214 || fileHeader.cwtv == 0)
  544. && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0
  545. && fileHeader.pwd == 0 && fileHeader.reserved == 0
  546. && (fileHeader.flags & (ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig)) == 0;
  547. if(possiblyUNMO3 && fileHeader.insnum == 0 && fileHeader.smpnum > 0 && file.GetPosition() + 4 * smpPos.size() + 2 <= minPtr)
  548. {
  549. // UNMO3 < v2.4.0.1 reserves some space for instrument parapointers even in sample mode.
  550. // This makes reading MIDI macros and plugin information impossible.
  551. // Note: While UNMO3 and CheeseTracker header fingerprints are almost identical, we cannot mis-detect CheeseTracker here,
  552. // as it always sets the instrument mode flag and writes non-zero row highlights.
  553. bool oldUNMO3 = true;
  554. for(uint16 i = 0; i < fileHeader.smpnum; i++)
  555. {
  556. if(file.ReadUint32LE() != 0)
  557. {
  558. oldUNMO3 = false;
  559. file.SkipBack(4 + i * 4);
  560. break;
  561. }
  562. }
  563. if(oldUNMO3)
  564. {
  565. madeWithTracker = U_("UNMO3 <= 2.4");
  566. }
  567. }
  568. if(possiblyUNMO3 && fileHeader.cwtv == 0)
  569. {
  570. madeWithTracker = U_("UNMO3 v0/1");
  571. }
  572. // Reading IT Edit History Info
  573. // This is only supposed to be present if bit 1 of the special flags is set.
  574. // However, old versions of Schism and probably other trackers always set this bit
  575. // even if they don't write the edit history count. So we have to filter this out...
  576. // This is done by looking at the parapointers. If the history data ends after
  577. // the first parapointer, we assume that it's actually no history data.
  578. if(fileHeader.special & ITFileHeader::embedEditHistory)
  579. {
  580. const uint16 nflt = file.ReadUint16LE();
  581. if(file.CanRead(nflt * sizeof(ITHistoryStruct)) && file.GetPosition() + nflt * sizeof(ITHistoryStruct) <= minPtr)
  582. {
  583. m_FileHistory.resize(nflt);
  584. for(auto &mptHistory : m_FileHistory)
  585. {
  586. ITHistoryStruct itHistory;
  587. file.ReadStruct(itHistory);
  588. itHistory.ConvertToMPT(mptHistory);
  589. }
  590. if(possiblyUNMO3 && nflt == 0)
  591. {
  592. if(fileHeader.special & ITFileHeader::embedPatternHighlights)
  593. madeWithTracker = U_("UNMO3 <= 2.4.0.1"); // Set together with MIDI macro embed flag
  594. else
  595. madeWithTracker = U_("UNMO3"); // Either 2.4.0.2+ or no MIDI macros embedded
  596. }
  597. } else
  598. {
  599. // Oops, we were not supposed to read this.
  600. file.SkipBack(2);
  601. }
  602. } else if(possiblyUNMO3 && fileHeader.special <= 1)
  603. {
  604. // UNMO3 < v2.4.0.1 will set the edit history special bit iff the MIDI macro embed bit is also set,
  605. // but it always writes the two extra bytes for the edit history length (zeroes).
  606. // If MIDI macros are embedded, we are fine and end up in the first case of the if statement (read edit history).
  607. // Otherwise we end up here and might have to read the edit history length.
  608. if(file.ReadUint16LE() == 0)
  609. {
  610. madeWithTracker = U_("UNMO3 <= 2.4");
  611. } else
  612. {
  613. // These were not zero bytes, but potentially belong to the upcoming MIDI config - need to skip back.
  614. // I think the only application that could end up here is CheeseTracker, if it allows to write 0 for both row highlight values.
  615. // IT 2.14 itself will always write the edit history.
  616. file.SkipBack(2);
  617. }
  618. }
  619. // Reading MIDI Output & Macros
  620. bool hasMidiConfig = (fileHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (fileHeader.special & ITFileHeader::embedMIDIConfiguration);
  621. if(hasMidiConfig && file.ReadStruct<MIDIMacroConfigData>(m_MidiCfg))
  622. {
  623. m_MidiCfg.Sanitize();
  624. }
  625. // Ignore MIDI data. Fixes some files like denonde.it that were made with old versions of Impulse Tracker (which didn't support Zxx filters) and have Zxx effects in the patterns.
  626. if(fileHeader.cwtv < 0x0214)
  627. {
  628. m_MidiCfg.ClearZxxMacros();
  629. }
  630. // Read pattern names: "PNAM"
  631. FileReader patNames;
  632. if(file.ReadMagic("PNAM"))
  633. {
  634. patNames = file.ReadChunk(file.ReadUint32LE());
  635. }
  636. m_nChannels = 1;
  637. // Read channel names: "CNAM"
  638. if(file.ReadMagic("CNAM"))
  639. {
  640. FileReader chnNames = file.ReadChunk(file.ReadUint32LE());
  641. const CHANNELINDEX readChns = std::min(MAX_BASECHANNELS, static_cast<CHANNELINDEX>(chnNames.GetLength() / MAX_CHANNELNAME));
  642. m_nChannels = readChns;
  643. for(CHANNELINDEX i = 0; i < readChns; i++)
  644. {
  645. chnNames.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[i].szName, MAX_CHANNELNAME);
  646. }
  647. }
  648. // Read mix plugins information
  649. FileReader pluginChunk = file.ReadChunk((minPtr >= file.GetPosition()) ? minPtr - file.GetPosition() : file.BytesLeft());
  650. const bool isBeRoTracker = LoadMixPlugins(pluginChunk);
  651. // Read Song Message
  652. if((fileHeader.special & ITFileHeader::embedSongMessage) && fileHeader.msglength > 0 && file.Seek(fileHeader.msgoffset))
  653. {
  654. // Generally, IT files should use CR for line endings. However, ChibiTracker uses LF. One could do...
  655. // if(itHeader.cwtv == 0x0214 && itHeader.cmwt == 0x0214 && itHeader.reserved == ITFileHeader::chibiMagic) --> Chibi detected.
  656. // But we'll just use autodetection here:
  657. m_songMessage.Read(file, fileHeader.msglength, SongMessage::leAutodetect);
  658. }
  659. // Reading Instruments
  660. m_nInstruments = 0;
  661. if(fileHeader.flags & ITFileHeader::instrumentMode)
  662. {
  663. m_nInstruments = std::min(static_cast<INSTRUMENTINDEX>(fileHeader.insnum), static_cast<INSTRUMENTINDEX>(MAX_INSTRUMENTS - 1));
  664. }
  665. for(INSTRUMENTINDEX i = 0; i < GetNumInstruments(); i++)
  666. {
  667. if(insPos[i] > 0 && file.Seek(insPos[i]) && file.CanRead(fileHeader.cmwt < 0x200 ? sizeof(ITOldInstrument) : sizeof(ITInstrument)))
  668. {
  669. ModInstrument *instrument = AllocateInstrument(i + 1);
  670. if(instrument != nullptr)
  671. {
  672. ITInstrToMPT(file, *instrument, fileHeader.cmwt);
  673. // MIDI Pitch Wheel Depth is a global setting in IT. Apply it to all instruments.
  674. instrument->midiPWD = fileHeader.pwd;
  675. }
  676. }
  677. }
  678. // In order to properly compute the position, in file, of eventual extended settings
  679. // such as "attack" we need to keep the "real" size of the last sample as those extra
  680. // setting will follow this sample in the file
  681. FileReader::off_t lastSampleOffset = 0;
  682. if(fileHeader.smpnum > 0)
  683. {
  684. lastSampleOffset = smpPos[fileHeader.smpnum - 1] + sizeof(ITSample);
  685. }
  686. bool possibleXMconversion = false;
  687. // Reading Samples
  688. m_nSamples = std::min(static_cast<SAMPLEINDEX>(fileHeader.smpnum), static_cast<SAMPLEINDEX>(MAX_SAMPLES - 1));
  689. bool lastSampleCompressed = false;
  690. for(SAMPLEINDEX i = 0; i < GetNumSamples(); i++)
  691. {
  692. ITSample sampleHeader;
  693. if(smpPos[i] > 0 && file.Seek(smpPos[i]) && file.ReadStruct(sampleHeader))
  694. {
  695. // IT does not check for the IMPS magic, and some bad XM->IT converter out there doesn't write the magic bytes for empty sample slots.
  696. ModSample &sample = Samples[i + 1];
  697. size_t sampleOffset = sampleHeader.ConvertToMPT(sample);
  698. m_szNames[i + 1] = mpt::String::ReadBuf(mpt::String::spacePadded, sampleHeader.name);
  699. if(!file.Seek(sampleOffset))
  700. continue;
  701. lastSampleCompressed = false;
  702. if(sample.uFlags[CHN_ADLIB])
  703. {
  704. // FM instrument in MPTM
  705. OPLPatch patch;
  706. if(file.ReadArray(patch))
  707. {
  708. sample.SetAdlib(true, patch);
  709. }
  710. } else if(!sample.uFlags[SMP_KEEPONDISK])
  711. {
  712. SampleIO sampleIO = sampleHeader.GetSampleFormat(fileHeader.cwtv);
  713. if(loadFlags & loadSampleData)
  714. {
  715. sampleIO.ReadSample(sample, file);
  716. } else
  717. {
  718. if(sampleIO.IsVariableLengthEncoded())
  719. lastSampleCompressed = true;
  720. else
  721. file.Skip(sampleIO.CalculateEncodedSize(sample.nLength));
  722. }
  723. if(sampleIO.GetEncoding() == SampleIO::unsignedPCM && sample.nLength != 0)
  724. {
  725. // There is some XM to IT converter (don't know which one) and it identifies as IT 2.04.
  726. // The only safe way to distinguish it from an IT-saved file are the unsigned samples.
  727. possibleXMconversion = true;
  728. }
  729. } else
  730. {
  731. // External sample in MPTM file
  732. size_t strLen;
  733. file.ReadVarInt(strLen);
  734. if((loadFlags & loadSampleData) && strLen)
  735. {
  736. std::string filenameU8;
  737. file.ReadString<mpt::String::maybeNullTerminated>(filenameU8, strLen);
  738. #if defined(MPT_EXTERNAL_SAMPLES)
  739. SetSamplePath(i + 1, mpt::PathString::FromUTF8(filenameU8));
  740. #elif !defined(LIBOPENMPT_BUILD_TEST)
  741. AddToLog(LogWarning, MPT_UFORMAT("Loading external sample {} ('{}') failed: External samples are not supported.")(i + 1, mpt::ToUnicode(mpt::Charset::UTF8, filenameU8)));
  742. #endif // MPT_EXTERNAL_SAMPLES
  743. } else
  744. {
  745. file.Skip(strLen);
  746. }
  747. }
  748. lastSampleOffset = std::max(lastSampleOffset, file.GetPosition());
  749. }
  750. }
  751. m_nSamples = std::max(SAMPLEINDEX(1), GetNumSamples());
  752. if(possibleXMconversion && fileHeader.cwtv == 0x0204 && fileHeader.cmwt == 0x0200 && fileHeader.special == 0 && fileHeader.reserved == 0
  753. && (fileHeader.flags & ~ITFileHeader::linearSlides) == (ITFileHeader::useStereoPlayback | ITFileHeader::instrumentMode | ITFileHeader::itOldEffects)
  754. && fileHeader.globalvol == 128 && fileHeader.mv == 48 && fileHeader.sep == 128 && fileHeader.pwd == 0 && fileHeader.msglength == 0)
  755. {
  756. for(uint8 pan : fileHeader.chnpan)
  757. {
  758. if(pan != 0x20 && pan != 0xA0)
  759. possibleXMconversion = false;
  760. }
  761. for(uint8 vol : fileHeader.chnvol)
  762. {
  763. if(vol != 0x40)
  764. possibleXMconversion = false;
  765. }
  766. for(size_t i = 20; i < std::size(fileHeader.songname); i++)
  767. {
  768. if(fileHeader.songname[i] != 0)
  769. possibleXMconversion = false;
  770. }
  771. if(possibleXMconversion)
  772. madeWithTracker = U_("XM Conversion");
  773. }
  774. m_nMinPeriod = 0;
  775. m_nMaxPeriod = int32_max;
  776. PATTERNINDEX numPats = std::min(static_cast<PATTERNINDEX>(patPos.size()), GetModSpecifications().patternsMax);
  777. if(numPats != patPos.size())
  778. {
  779. // Hack: Notify user here if file contains more patterns than what can be read.
  780. AddToLog(LogWarning, MPT_UFORMAT("The module contains {} patterns but only {} patterns can be loaded in this OpenMPT version.")(patPos.size(), numPats));
  781. }
  782. if(!(loadFlags & loadPatternData))
  783. {
  784. numPats = 0;
  785. }
  786. // Checking for number of used channels, which is not explicitely specified in the file.
  787. for(PATTERNINDEX pat = 0; pat < numPats; pat++)
  788. {
  789. if(patPos[pat] == 0 || !file.Seek(patPos[pat]))
  790. continue;
  791. uint16 len = file.ReadUint16LE();
  792. ROWINDEX numRows = file.ReadUint16LE();
  793. if(numRows < 1
  794. || numRows > MAX_PATTERN_ROWS
  795. || !file.Skip(4))
  796. continue;
  797. FileReader patternData = file.ReadChunk(len);
  798. ROWINDEX row = 0;
  799. std::vector<uint8> chnMask(GetNumChannels());
  800. while(row < numRows && patternData.CanRead(1))
  801. {
  802. uint8 b = patternData.ReadUint8();
  803. if(!b)
  804. {
  805. row++;
  806. continue;
  807. }
  808. CHANNELINDEX ch = (b & IT_bitmask_patternChanField_c); // 0x7f We have some data grab a byte keeping only 7 bits
  809. if(ch)
  810. {
  811. ch = (ch - 1);// & IT_bitmask_patternChanMask_c; // 0x3f mask of the byte again, keeping only 6 bits
  812. }
  813. if(ch >= chnMask.size())
  814. {
  815. chnMask.resize(ch + 1, 0);
  816. }
  817. if(b & IT_bitmask_patternChanEnabled_c) // 0x80 check if the upper bit is enabled.
  818. {
  819. chnMask[ch] = patternData.ReadUint8(); // set the channel mask for this channel.
  820. }
  821. // Channel used
  822. if(chnMask[ch] & 0x0F) // if this channel is used set m_nChannels
  823. {
  824. if(ch >= GetNumChannels() && ch < MAX_BASECHANNELS)
  825. {
  826. m_nChannels = ch + 1;
  827. }
  828. }
  829. // Now we actually update the pattern-row entry the note,instrument etc.
  830. // Note
  831. if(chnMask[ch] & 1)
  832. patternData.Skip(1);
  833. // Instrument
  834. if(chnMask[ch] & 2)
  835. patternData.Skip(1);
  836. // Volume
  837. if(chnMask[ch] & 4)
  838. patternData.Skip(1);
  839. // Effect
  840. if(chnMask[ch] & 8)
  841. patternData.Skip(2);
  842. }
  843. lastSampleOffset = std::max(lastSampleOffset, file.GetPosition());
  844. }
  845. // Compute extra instruments settings position
  846. if(lastSampleOffset > 0)
  847. {
  848. file.Seek(lastSampleOffset);
  849. if(lastSampleCompressed)
  850. {
  851. // If the last sample was compressed, we do not know where it ends.
  852. // Hence, in case we decided not to decode the sample data, we now
  853. // have to emulate this until we reach EOF or some instrument / song properties.
  854. while(file.CanRead(4))
  855. {
  856. if(file.ReadMagic("XTPM") || file.ReadMagic("STPM"))
  857. {
  858. uint32 id = file.ReadUint32LE();
  859. file.SkipBack(8);
  860. // Our chunk IDs should only contain ASCII characters
  861. if(!(id & 0x80808080) && (id & 0x60606060))
  862. {
  863. break;
  864. }
  865. }
  866. file.Skip(file.ReadUint16LE());
  867. }
  868. }
  869. }
  870. // Load instrument and song extensions.
  871. interpretModPlugMade |= LoadExtendedInstrumentProperties(file);
  872. if(interpretModPlugMade && !isBeRoTracker)
  873. {
  874. m_playBehaviour.reset();
  875. m_nMixLevels = MixLevels::Original;
  876. }
  877. // Need to do this before reading the patterns because m_nChannels might be modified by LoadExtendedSongProperties. *sigh*
  878. LoadExtendedSongProperties(file, false, &interpretModPlugMade);
  879. // Reading Patterns
  880. Patterns.ResizeArray(numPats);
  881. for(PATTERNINDEX pat = 0; pat < numPats; pat++)
  882. {
  883. if(patPos[pat] == 0 || !file.Seek(patPos[pat]))
  884. {
  885. // Empty 64-row pattern
  886. if(!Patterns.Insert(pat, 64))
  887. {
  888. AddToLog(LogWarning, MPT_UFORMAT("Allocating patterns failed starting from pattern {}")(pat));
  889. break;
  890. }
  891. // Now (after the Insert() call), we can read the pattern name.
  892. CopyPatternName(Patterns[pat], patNames);
  893. continue;
  894. }
  895. uint16 len = file.ReadUint16LE();
  896. ROWINDEX numRows = file.ReadUint16LE();
  897. if(!file.Skip(4)
  898. || !Patterns.Insert(pat, numRows))
  899. continue;
  900. FileReader patternData = file.ReadChunk(len);
  901. // Now (after the Insert() call), we can read the pattern name.
  902. CopyPatternName(Patterns[pat], patNames);
  903. std::vector<uint8> chnMask(GetNumChannels());
  904. std::vector<ModCommand> lastValue(GetNumChannels(), ModCommand::Empty());
  905. auto patData = Patterns[pat].begin();
  906. ROWINDEX row = 0;
  907. while(row < numRows && patternData.CanRead(1))
  908. {
  909. uint8 b = patternData.ReadUint8();
  910. if(!b)
  911. {
  912. row++;
  913. patData += GetNumChannels();
  914. continue;
  915. }
  916. CHANNELINDEX ch = b & IT_bitmask_patternChanField_c; // 0x7f
  917. if(ch)
  918. {
  919. ch = (ch - 1); //& IT_bitmask_patternChanMask_c; // 0x3f
  920. }
  921. if(ch >= chnMask.size())
  922. {
  923. chnMask.resize(ch + 1, 0);
  924. lastValue.resize(ch + 1, ModCommand::Empty());
  925. MPT_ASSERT(chnMask.size() <= GetNumChannels());
  926. }
  927. if(b & IT_bitmask_patternChanEnabled_c) // 0x80
  928. {
  929. chnMask[ch] = patternData.ReadUint8();
  930. }
  931. // Now we grab the data for this particular row/channel.
  932. ModCommand dummy = ModCommand::Empty();
  933. ModCommand &m = ch < m_nChannels ? patData[ch] : dummy;
  934. if(chnMask[ch] & 0x10)
  935. {
  936. m.note = lastValue[ch].note;
  937. }
  938. if(chnMask[ch] & 0x20)
  939. {
  940. m.instr = lastValue[ch].instr;
  941. }
  942. if(chnMask[ch] & 0x40)
  943. {
  944. m.volcmd = lastValue[ch].volcmd;
  945. m.vol = lastValue[ch].vol;
  946. }
  947. if(chnMask[ch] & 0x80)
  948. {
  949. m.command = lastValue[ch].command;
  950. m.param = lastValue[ch].param;
  951. }
  952. if(chnMask[ch] & 1) // Note
  953. {
  954. uint8 note = patternData.ReadUint8();
  955. if(note < 0x80)
  956. note += NOTE_MIN;
  957. if(!(GetType() & MOD_TYPE_MPT))
  958. {
  959. if(note > NOTE_MAX && note < 0xFD) note = NOTE_FADE;
  960. else if(note == 0xFD) note = NOTE_NONE;
  961. }
  962. m.note = note;
  963. lastValue[ch].note = note;
  964. }
  965. if(chnMask[ch] & 2)
  966. {
  967. uint8 instr = patternData.ReadUint8();
  968. m.instr = instr;
  969. lastValue[ch].instr = instr;
  970. }
  971. if(chnMask[ch] & 4)
  972. {
  973. uint8 vol = patternData.ReadUint8();
  974. // 0-64: Set Volume
  975. if(vol <= 64) { m.volcmd = VOLCMD_VOLUME; m.vol = vol; } else
  976. // 128-192: Set Panning
  977. if(vol >= 128 && vol <= 192) { m.volcmd = VOLCMD_PANNING; m.vol = vol - 128; } else
  978. // 65-74: Fine Volume Up
  979. if(vol < 75) { m.volcmd = VOLCMD_FINEVOLUP; m.vol = vol - 65; } else
  980. // 75-84: Fine Volume Down
  981. if(vol < 85) { m.volcmd = VOLCMD_FINEVOLDOWN; m.vol = vol - 75; } else
  982. // 85-94: Volume Slide Up
  983. if(vol < 95) { m.volcmd = VOLCMD_VOLSLIDEUP; m.vol = vol - 85; } else
  984. // 95-104: Volume Slide Down
  985. if(vol < 105) { m.volcmd = VOLCMD_VOLSLIDEDOWN; m.vol = vol - 95; } else
  986. // 105-114: Pitch Slide Up
  987. if(vol < 115) { m.volcmd = VOLCMD_PORTADOWN; m.vol = vol - 105; } else
  988. // 115-124: Pitch Slide Down
  989. if(vol < 125) { m.volcmd = VOLCMD_PORTAUP; m.vol = vol - 115; } else
  990. // 193-202: Portamento To
  991. if(vol >= 193 && vol <= 202) { m.volcmd = VOLCMD_TONEPORTAMENTO; m.vol = vol - 193; } else
  992. // 203-212: Vibrato depth
  993. if(vol >= 203 && vol <= 212)
  994. {
  995. m.volcmd = VOLCMD_VIBRATODEPTH;
  996. m.vol = vol - 203;
  997. // Old versions of ModPlug saved this as vibrato speed instead, so let's fix that.
  998. if(m.vol && m_dwLastSavedWithVersion && m_dwLastSavedWithVersion <= MPT_V("1.17.02.54"))
  999. m.volcmd = VOLCMD_VIBRATOSPEED;
  1000. } else
  1001. // 213-222: Unused (was velocity)
  1002. // 223-232: Offset
  1003. if(vol >= 223 && vol <= 232) { m.volcmd = VOLCMD_OFFSET; m.vol = vol - 223; }
  1004. lastValue[ch].volcmd = m.volcmd;
  1005. lastValue[ch].vol = m.vol;
  1006. }
  1007. // Reading command/param
  1008. if(chnMask[ch] & 8)
  1009. {
  1010. const auto [command, param] = patternData.ReadArray<uint8, 2>();
  1011. m.command = command;
  1012. m.param = param;
  1013. S3MConvert(m, true);
  1014. // In some IT-compatible trackers, it is possible to input a parameter without a command.
  1015. // In this case, we still need to update the last value memory. OpenMPT didn't do this until v1.25.01.07.
  1016. // Example: ckbounce.it
  1017. lastValue[ch].command = m.command;
  1018. lastValue[ch].param = m.param;
  1019. }
  1020. }
  1021. }
  1022. if(!m_dwLastSavedWithVersion && fileHeader.cwtv == 0x0888)
  1023. {
  1024. // Up to OpenMPT 1.17.02.45 (r165), it was possible that the "last saved with" field was 0
  1025. // when saving a file in OpenMPT for the first time.
  1026. m_dwLastSavedWithVersion = MPT_V("1.17.00.00");
  1027. }
  1028. if(m_dwLastSavedWithVersion && madeWithTracker.empty())
  1029. {
  1030. madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion);
  1031. if(memcmp(&fileHeader.reserved, "OMPT", 4) && (fileHeader.cwtv & 0xF000) == 0x5000)
  1032. {
  1033. madeWithTracker += U_(" (compatibility export)");
  1034. } else if(m_dwLastSavedWithVersion.IsTestVersion())
  1035. {
  1036. madeWithTracker += U_(" (test build)");
  1037. }
  1038. } else
  1039. {
  1040. const int32 schismDateVersion = SchismTrackerEpoch + ((fileHeader.cwtv == 0x1FFF) ? fileHeader.reserved : (fileHeader.cwtv - 0x1050));
  1041. switch(fileHeader.cwtv >> 12)
  1042. {
  1043. case 0:
  1044. if(isBeRoTracker)
  1045. {
  1046. // Old versions
  1047. madeWithTracker = U_("BeRoTracker");
  1048. } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && fileHeader.flags == 9 && fileHeader.special == 0
  1049. && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0
  1050. && fileHeader.insnum == 0 && fileHeader.patnum + 1 == fileHeader.ordnum
  1051. && fileHeader.globalvol == 128 && fileHeader.mv == 100 && fileHeader.speed == 1 && fileHeader.sep == 128 && fileHeader.pwd == 0
  1052. && fileHeader.msglength == 0 && fileHeader.msgoffset == 0 && fileHeader.reserved == 0)
  1053. {
  1054. madeWithTracker = U_("OpenSPC conversion");
  1055. } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.reserved == 0)
  1056. {
  1057. // ModPlug Tracker 1.00a5, instruments 560 bytes apart
  1058. m_dwLastSavedWithVersion = MPT_V("1.00.00.A5");
  1059. madeWithTracker = U_("ModPlug Tracker 1.00a5");
  1060. interpretModPlugMade = true;
  1061. } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && !memcmp(&fileHeader.reserved, "CHBI", 4))
  1062. {
  1063. madeWithTracker = U_("ChibiTracker");
  1064. m_playBehaviour.reset(kITShortSampleRetrig);
  1065. } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0214 && fileHeader.special <= 1 && fileHeader.pwd == 0 && fileHeader.reserved == 0
  1066. && (fileHeader.flags & (ITFileHeader::vol0Optimisations | ITFileHeader::instrumentMode | ITFileHeader::useMIDIPitchController | ITFileHeader::reqEmbeddedMIDIConfig | ITFileHeader::extendedFilterRange)) == ITFileHeader::instrumentMode
  1067. && m_nSamples > 0 && (Samples[1].filename == "XXXXXXXX.YYY"))
  1068. {
  1069. madeWithTracker = U_("CheeseTracker");
  1070. } else if(fileHeader.cwtv == 0 && madeWithTracker.empty())
  1071. {
  1072. madeWithTracker = U_("Unknown");
  1073. } else if(fileHeader.cmwt < 0x0300 && madeWithTracker.empty())
  1074. {
  1075. if(fileHeader.cmwt > 0x0214)
  1076. {
  1077. madeWithTracker = U_("Impulse Tracker 2.15");
  1078. } else if(fileHeader.cwtv > 0x0214)
  1079. {
  1080. // Patched update of IT 2.14 (0x0215 - 0x0217 == p1 - p3)
  1081. // p4 (as found on modland) adds the ITVSOUND driver, but doesn't seem to change
  1082. // anything as far as file saving is concerned.
  1083. madeWithTracker = MPT_UFORMAT("Impulse Tracker 2.14p{}")(fileHeader.cwtv - 0x0214);
  1084. } else
  1085. {
  1086. madeWithTracker = MPT_UFORMAT("Impulse Tracker {}.{}")((fileHeader.cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>((fileHeader.cwtv & 0xFF)));
  1087. }
  1088. if(m_FileHistory.empty() && fileHeader.reserved != 0)
  1089. {
  1090. // Starting from version 2.07, IT stores the total edit time of a module in the "reserved" field
  1091. uint32 editTime = DecodeITEditTimer(fileHeader.cwtv, fileHeader.reserved);
  1092. FileHistory hist;
  1093. hist.openTime = static_cast<uint32>(editTime * (HISTORY_TIMER_PRECISION / 18.2));
  1094. m_FileHistory.push_back(hist);
  1095. }
  1096. }
  1097. break;
  1098. case 1:
  1099. madeWithTracker = GetSchismTrackerVersion(fileHeader.cwtv, fileHeader.reserved);
  1100. // Hertz in linear mode: Added 2015-01-29, https://github.com/schismtracker/schismtracker/commit/671b30311082a0e7df041fca25f989b5d2478f69
  1101. if(schismDateVersion < SchismVersionFromDate<2015, 01, 29>::date && m_SongFlags[SONG_LINEARSLIDES])
  1102. m_playBehaviour.reset(kPeriodsAreHertz);
  1103. // Hertz in Amiga mode: Added 2021-05-02, https://github.com/schismtracker/schismtracker/commit/c656a6cbd5aaf81198a7580faf81cb7960cb6afa
  1104. else if(schismDateVersion < SchismVersionFromDate<2021, 05, 02>::date && !m_SongFlags[SONG_LINEARSLIDES])
  1105. m_playBehaviour.reset(kPeriodsAreHertz);
  1106. // Qxx with short samples: Added 2016-05-13, https://github.com/schismtracker/schismtracker/commit/e7b1461fe751554309fd403713c2a1ef322105ca
  1107. if(schismDateVersion < SchismVersionFromDate<2016, 05, 13>::date)
  1108. m_playBehaviour.reset(kITShortSampleRetrig);
  1109. // Instrument pan doesn't override channel pan: Added 2021-05-02, https://github.com/schismtracker/schismtracker/commit/a34ec86dc819915debc9e06f4727b77bf2dd29ee
  1110. if(schismDateVersion < SchismVersionFromDate<2021, 05, 02>::date)
  1111. m_playBehaviour.reset(kITDoNotOverrideChannelPan);
  1112. // Notes set instrument panning, not instrument numbers: Added 2021-05-02, https://github.com/schismtracker/schismtracker/commit/648f5116f984815c69e11d018b32dfec53c6b97a
  1113. if(schismDateVersion < SchismVersionFromDate<2021, 05, 02>::date)
  1114. m_playBehaviour.reset(kITPanningReset);
  1115. // Imprecise calculation of ping-pong loop wraparound: Added 2021-11-01, https://github.com/schismtracker/schismtracker/commit/22cbb9b676e9c2c9feb7a6a17deca7a17ac138cc
  1116. if(schismDateVersion < SchismVersionFromDate<2021, 11, 01>::date)
  1117. m_playBehaviour.set(kImprecisePingPongLoops);
  1118. // Pitch/Pan Separation can be overridden by panning commands: Added 2021-11-01, https://github.com/schismtracker/schismtracker/commit/6e9f1207015cae0fe1b829fff7bb867e02ec6dea
  1119. if(schismDateVersion < SchismVersionFromDate<2021, 11, 01>::date)
  1120. m_playBehaviour.reset(kITPitchPanSeparation);
  1121. break;
  1122. case 4:
  1123. madeWithTracker = MPT_UFORMAT("pyIT {}.{}")((fileHeader.cwtv & 0x0F00) >> 8, mpt::ufmt::hex0<2>(fileHeader.cwtv & 0xFF));
  1124. break;
  1125. case 6:
  1126. madeWithTracker = U_("BeRoTracker");
  1127. break;
  1128. case 7:
  1129. if(fileHeader.cwtv == 0x7FFF && fileHeader.cmwt == 0x0215)
  1130. madeWithTracker = U_("munch.py");
  1131. else
  1132. madeWithTracker = MPT_UFORMAT("ITMCK {}.{}.{}")((fileHeader.cwtv >> 8) & 0x0F, (fileHeader.cwtv >> 4) & 0x0F, fileHeader.cwtv & 0x0F);
  1133. break;
  1134. case 0xD:
  1135. madeWithTracker = U_("spc2it");
  1136. break;
  1137. }
  1138. }
  1139. if(GetType() == MOD_TYPE_MPT)
  1140. {
  1141. // START - mpt specific:
  1142. if(fileHeader.cwtv > 0x0889 && file.Seek(mptStartPos))
  1143. {
  1144. LoadMPTMProperties(file, fileHeader.cwtv);
  1145. }
  1146. }
  1147. m_modFormat.formatName = (GetType() == MOD_TYPE_MPT) ? U_("OpenMPT MPTM") : MPT_UFORMAT("Impulse Tracker {}.{}")(fileHeader.cmwt >> 8, mpt::ufmt::hex0<2>(fileHeader.cmwt & 0xFF));
  1148. m_modFormat.type = (GetType() == MOD_TYPE_MPT) ? U_("mptm") : U_("it");
  1149. m_modFormat.madeWithTracker = std::move(madeWithTracker);
  1150. m_modFormat.charset = m_dwLastSavedWithVersion ? mpt::Charset::Windows1252 : mpt::Charset::CP437;
  1151. return true;
  1152. }
  1153. void CSoundFile::LoadMPTMProperties(FileReader &file, uint16 cwtv)
  1154. {
  1155. std::istringstream iStrm(mpt::buffer_cast<std::string>(file.GetRawDataAsByteVector()));
  1156. if(cwtv >= 0x88D)
  1157. {
  1158. srlztn::SsbRead ssb(iStrm);
  1159. ssb.BeginRead("mptm", Version::Current().GetRawVersion());
  1160. int8 useUTF8Tuning = 0;
  1161. ssb.ReadItem(useUTF8Tuning, "UTF8Tuning");
  1162. mpt::Charset TuningCharset = useUTF8Tuning ? mpt::Charset::UTF8 : GetCharsetInternal();
  1163. ssb.ReadItem(GetTuneSpecificTunings(), "0", [TuningCharset](std::istream &iStrm, CTuningCollection &tc, const std::size_t dummy){ return ReadTuningCollection(iStrm, tc, dummy, TuningCharset); });
  1164. ssb.ReadItem(*this, "1", [TuningCharset](std::istream& iStrm, CSoundFile& csf, const std::size_t dummy){ return ReadTuningMap(iStrm, csf, dummy, TuningCharset); });
  1165. ssb.ReadItem(Order, "2", &ReadModSequenceOld);
  1166. ssb.ReadItem(Patterns, FileIdPatterns, &ReadModPatterns);
  1167. mpt::Charset sequenceDefaultCharset = GetCharsetInternal();
  1168. ssb.ReadItem(Order, FileIdSequences, [sequenceDefaultCharset](std::istream &iStrm, ModSequenceSet &seq, std::size_t nSize){ return ReadModSequences(iStrm, seq, nSize, sequenceDefaultCharset); });
  1169. if(ssb.GetStatus() & srlztn::SNT_FAILURE)
  1170. {
  1171. AddToLog(LogError, U_("Unknown error occurred while deserializing file."));
  1172. }
  1173. } else
  1174. {
  1175. // Loading for older files.
  1176. mpt::ustring name;
  1177. if(GetTuneSpecificTunings().Deserialize(iStrm, name, GetCharsetInternal()) != Tuning::SerializationResult::Success)
  1178. {
  1179. AddToLog(LogError, U_("Loading tune specific tunings failed."));
  1180. } else
  1181. {
  1182. ReadTuningMapImpl(iStrm, *this, GetCharsetInternal(), 0, cwtv < 0x88C);
  1183. }
  1184. }
  1185. }
  1186. #ifndef MODPLUG_NO_FILESAVE
  1187. // Save edit history. Pass a null pointer for *f to retrieve the number of bytes that would be written.
  1188. static uint32 SaveITEditHistory(const CSoundFile &sndFile, std::ostream *file)
  1189. {
  1190. size_t num = sndFile.GetFileHistory().size();
  1191. #ifdef MODPLUG_TRACKER
  1192. const CModDoc *pModDoc = sndFile.GetpModDoc();
  1193. num += (pModDoc != nullptr) ? 1 : 0; // + 1 for this session
  1194. #endif // MODPLUG_TRACKER
  1195. uint16 fnum = mpt::saturate_cast<uint16>(num); // Number of entries that are actually going to be written
  1196. const uint32 bytesWritten = 2 + fnum * 8; // Number of bytes that are actually going to be written
  1197. if(!file)
  1198. {
  1199. return bytesWritten;
  1200. }
  1201. std::ostream & f = *file;
  1202. // Write number of history entries
  1203. mpt::IO::WriteIntLE(f, fnum);
  1204. // Write history data
  1205. const size_t start = (num > uint16_max) ? num - uint16_max : 0;
  1206. for(size_t n = start; n < num; n++)
  1207. {
  1208. FileHistory mptHistory;
  1209. #ifdef MODPLUG_TRACKER
  1210. if(n < sndFile.GetFileHistory().size())
  1211. #endif // MODPLUG_TRACKER
  1212. {
  1213. // Previous timestamps
  1214. mptHistory = sndFile.GetFileHistory()[n];
  1215. #ifdef MODPLUG_TRACKER
  1216. } else if(pModDoc != nullptr)
  1217. {
  1218. // Current ("new") timestamp
  1219. const time_t creationTime = pModDoc->GetCreationTime();
  1220. MemsetZero(mptHistory.loadDate);
  1221. //localtime_s(&loadDate, &creationTime);
  1222. const tm* const p = localtime(&creationTime);
  1223. if (p != nullptr)
  1224. mptHistory.loadDate = *p;
  1225. else
  1226. sndFile.AddToLog(LogError, U_("Unable to retrieve current time."));
  1227. mptHistory.openTime = (uint32)(difftime(time(nullptr), creationTime) * HISTORY_TIMER_PRECISION);
  1228. #endif // MODPLUG_TRACKER
  1229. }
  1230. ITHistoryStruct itHistory;
  1231. itHistory.ConvertToIT(mptHistory);
  1232. mpt::IO::Write(f, itHistory);
  1233. }
  1234. return bytesWritten;
  1235. }
  1236. bool CSoundFile::SaveIT(std::ostream &f, const mpt::PathString &filename, bool compatibilityExport)
  1237. {
  1238. const CModSpecifications &specs = (GetType() == MOD_TYPE_MPT ? ModSpecs::mptm : (compatibilityExport ? ModSpecs::it : ModSpecs::itEx));
  1239. uint32 dwChnNamLen;
  1240. ITFileHeader itHeader;
  1241. uint64 dwPos = 0;
  1242. uint32 dwHdrPos = 0, dwExtra = 0;
  1243. // Writing Header
  1244. MemsetZero(itHeader);
  1245. dwChnNamLen = 0;
  1246. memcpy(itHeader.id, "IMPM", 4);
  1247. mpt::String::WriteBuf(mpt::String::nullTerminated, itHeader.songname) = m_songName;
  1248. itHeader.highlight_minor = mpt::saturate_cast<uint8>(m_nDefaultRowsPerBeat);
  1249. itHeader.highlight_major = mpt::saturate_cast<uint8>(m_nDefaultRowsPerMeasure);
  1250. if(GetType() == MOD_TYPE_MPT)
  1251. {
  1252. itHeader.ordnum = Order().GetLengthTailTrimmed();
  1253. if(Order().NeedsExtraDatafield() && itHeader.ordnum > 256)
  1254. {
  1255. // If there are more order items, write them elsewhere.
  1256. itHeader.ordnum = 256;
  1257. }
  1258. } else
  1259. {
  1260. // An additional "---" pattern is appended so Impulse Tracker won't ignore the last order item.
  1261. // Interestingly, this can exceed IT's 256 order limit. Also, IT will always save at least two orders.
  1262. itHeader.ordnum = std::min(Order().GetLengthTailTrimmed(), specs.ordersMax) + 1;
  1263. if(itHeader.ordnum < 2)
  1264. itHeader.ordnum = 2;
  1265. }
  1266. itHeader.insnum = std::min(m_nInstruments, specs.instrumentsMax);
  1267. itHeader.smpnum = std::min(m_nSamples, specs.samplesMax);
  1268. itHeader.patnum = std::min(Patterns.GetNumPatterns(), specs.patternsMax);
  1269. // Parapointers
  1270. std::vector<uint32le> patpos(itHeader.patnum);
  1271. std::vector<uint32le> smppos(itHeader.smpnum);
  1272. std::vector<uint32le> inspos(itHeader.insnum);
  1273. //VERSION
  1274. if(GetType() == MOD_TYPE_MPT)
  1275. {
  1276. // MPTM
  1277. itHeader.cwtv = verMptFileVer; // Used in OMPT-hack versioning.
  1278. itHeader.cmwt = 0x888;
  1279. } else
  1280. {
  1281. // IT
  1282. const uint32 mptVersion = Version::Current().GetRawVersion();
  1283. itHeader.cwtv = 0x5000 | static_cast<uint16>((mptVersion >> 16) & 0x0FFF); // format: txyy (t = tracker ID, x = version major, yy = version minor), e.g. 0x5117 (OpenMPT = 5, 117 = v1.17)
  1284. itHeader.cmwt = 0x0214; // Common compatible tracker :)
  1285. // Hack from schism tracker:
  1286. for(INSTRUMENTINDEX nIns = 1; nIns <= GetNumInstruments(); nIns++)
  1287. {
  1288. if(Instruments[nIns] && Instruments[nIns]->PitchEnv.dwFlags[ENV_FILTER])
  1289. {
  1290. itHeader.cmwt = 0x0216;
  1291. break;
  1292. }
  1293. }
  1294. if(compatibilityExport)
  1295. itHeader.reserved = mptVersion & 0xFFFF;
  1296. else
  1297. memcpy(&itHeader.reserved, "OMPT", 4);
  1298. }
  1299. itHeader.flags = ITFileHeader::useStereoPlayback | ITFileHeader::useMIDIPitchController;
  1300. itHeader.special = ITFileHeader::embedEditHistory | ITFileHeader::embedPatternHighlights;
  1301. if(m_nInstruments) itHeader.flags |= ITFileHeader::instrumentMode;
  1302. if(m_SongFlags[SONG_LINEARSLIDES]) itHeader.flags |= ITFileHeader::linearSlides;
  1303. if(m_SongFlags[SONG_ITOLDEFFECTS]) itHeader.flags |= ITFileHeader::itOldEffects;
  1304. if(m_SongFlags[SONG_ITCOMPATGXX]) itHeader.flags |= ITFileHeader::itCompatGxx;
  1305. if(m_SongFlags[SONG_EXFILTERRANGE] && !compatibilityExport) itHeader.flags |= ITFileHeader::extendedFilterRange;
  1306. itHeader.globalvol = static_cast<uint8>(m_nDefaultGlobalVolume / 2u);
  1307. itHeader.mv = static_cast<uint8>(std::min(m_nSamplePreAmp, uint32(128)));
  1308. itHeader.speed = mpt::saturate_cast<uint8>(m_nDefaultSpeed);
  1309. itHeader.tempo = mpt::saturate_cast<uint8>(m_nDefaultTempo.GetInt()); // We save the real tempo in an extension below if it exceeds 255.
  1310. itHeader.sep = 128; // pan separation
  1311. // IT doesn't have a per-instrument Pitch Wheel Depth setting, so we just store the first non-zero PWD setting in the header.
  1312. for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++)
  1313. {
  1314. if(Instruments[ins] != nullptr && Instruments[ins]->midiPWD != 0)
  1315. {
  1316. itHeader.pwd = static_cast<uint8>(std::abs(Instruments[ins]->midiPWD));
  1317. break;
  1318. }
  1319. }
  1320. dwHdrPos = sizeof(itHeader) + itHeader.ordnum;
  1321. // Channel Pan and Volume
  1322. memset(itHeader.chnpan, 0xA0, 64);
  1323. memset(itHeader.chnvol, 64, 64);
  1324. for(CHANNELINDEX ich = 0; ich < std::min(m_nChannels, CHANNELINDEX(64)); ich++) // Header only has room for settings for 64 chans...
  1325. {
  1326. itHeader.chnpan[ich] = (uint8)(ChnSettings[ich].nPan >> 2);
  1327. if (ChnSettings[ich].dwFlags[CHN_SURROUND]) itHeader.chnpan[ich] = 100;
  1328. itHeader.chnvol[ich] = (uint8)(ChnSettings[ich].nVolume);
  1329. #ifdef MODPLUG_TRACKER
  1330. if(TrackerSettings::Instance().MiscSaveChannelMuteStatus)
  1331. #endif
  1332. if (ChnSettings[ich].dwFlags[CHN_MUTE]) itHeader.chnpan[ich] |= 0x80;
  1333. }
  1334. // Channel names
  1335. if(!compatibilityExport)
  1336. {
  1337. for(CHANNELINDEX i = 0; i < m_nChannels; i++)
  1338. {
  1339. if(ChnSettings[i].szName[0])
  1340. {
  1341. dwChnNamLen = (i + 1) * MAX_CHANNELNAME;
  1342. }
  1343. }
  1344. if(dwChnNamLen) dwExtra += dwChnNamLen + 8;
  1345. }
  1346. if(!m_MidiCfg.IsMacroDefaultSetupUsed())
  1347. {
  1348. itHeader.flags |= ITFileHeader::reqEmbeddedMIDIConfig;
  1349. itHeader.special |= ITFileHeader::embedMIDIConfiguration;
  1350. dwExtra += sizeof(MIDIMacroConfigData);
  1351. }
  1352. // Pattern Names
  1353. const PATTERNINDEX numNamedPats = compatibilityExport ? 0 : Patterns.GetNumNamedPatterns();
  1354. if(numNamedPats > 0)
  1355. {
  1356. dwExtra += (numNamedPats * MAX_PATTERNNAME) + 8;
  1357. }
  1358. // Mix Plugins. Just calculate the size of this extra block for now.
  1359. if(!compatibilityExport)
  1360. {
  1361. dwExtra += SaveMixPlugins(nullptr, true);
  1362. }
  1363. // Edit History. Just calculate the size of this extra block for now.
  1364. dwExtra += SaveITEditHistory(*this, nullptr);
  1365. // Comments
  1366. uint16 msglength = 0;
  1367. if(!m_songMessage.empty())
  1368. {
  1369. itHeader.special |= ITFileHeader::embedSongMessage;
  1370. itHeader.msglength = msglength = mpt::saturate_cast<uint16>(m_songMessage.length() + 1u);
  1371. itHeader.msgoffset = dwHdrPos + dwExtra + (itHeader.insnum + itHeader.smpnum + itHeader.patnum) * 4;
  1372. }
  1373. // Write file header
  1374. mpt::IO::Write(f, itHeader);
  1375. Order().WriteAsByte(f, itHeader.ordnum);
  1376. mpt::IO::Write(f, inspos);
  1377. mpt::IO::Write(f, smppos);
  1378. mpt::IO::Write(f, patpos);
  1379. // Writing edit history information
  1380. SaveITEditHistory(*this, &f);
  1381. // Writing midi cfg
  1382. if(itHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig)
  1383. {
  1384. mpt::IO::Write(f, static_cast<MIDIMacroConfigData &>(m_MidiCfg));
  1385. }
  1386. // Writing pattern names
  1387. if(numNamedPats)
  1388. {
  1389. mpt::IO::WriteRaw(f, "PNAM", 4);
  1390. mpt::IO::WriteIntLE<uint32>(f, numNamedPats * MAX_PATTERNNAME);
  1391. for(PATTERNINDEX pat = 0; pat < numNamedPats; pat++)
  1392. {
  1393. char name[MAX_PATTERNNAME];
  1394. mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = Patterns[pat].GetName();
  1395. mpt::IO::Write(f, name);
  1396. }
  1397. }
  1398. // Writing channel names
  1399. if(dwChnNamLen && !compatibilityExport)
  1400. {
  1401. mpt::IO::WriteRaw(f, "CNAM", 4);
  1402. mpt::IO::WriteIntLE<uint32>(f, dwChnNamLen);
  1403. uint32 nChnNames = dwChnNamLen / MAX_CHANNELNAME;
  1404. for(uint32 inam = 0; inam < nChnNames; inam++)
  1405. {
  1406. char name[MAX_CHANNELNAME];
  1407. mpt::String::WriteBuf(mpt::String::maybeNullTerminated, name) = ChnSettings[inam].szName;
  1408. mpt::IO::Write(f, name);
  1409. }
  1410. }
  1411. // Writing mix plugins info
  1412. if(!compatibilityExport)
  1413. {
  1414. SaveMixPlugins(&f, false);
  1415. }
  1416. // Writing song message
  1417. dwPos = dwHdrPos + dwExtra + (itHeader.insnum + itHeader.smpnum + itHeader.patnum) * 4;
  1418. if(itHeader.special & ITFileHeader::embedSongMessage)
  1419. {
  1420. dwPos += msglength;
  1421. mpt::IO::WriteRaw(f, m_songMessage.c_str(), msglength);
  1422. }
  1423. // Writing instruments
  1424. const ModInstrument dummyInstr;
  1425. for(INSTRUMENTINDEX nins = 1; nins <= itHeader.insnum; nins++)
  1426. {
  1427. ITInstrumentEx iti;
  1428. uint32 instSize;
  1429. const ModInstrument &instr = (Instruments[nins] != nullptr) ? *Instruments[nins] : dummyInstr;
  1430. instSize = iti.ConvertToIT(instr, compatibilityExport, *this);
  1431. // Writing instrument
  1432. inspos[nins - 1] = static_cast<uint32>(dwPos);
  1433. dwPos += instSize;
  1434. mpt::IO::WritePartial(f, iti, instSize);
  1435. }
  1436. // Writing dummy sample headers (until we know the correct sample data offset)
  1437. ITSample itss;
  1438. MemsetZero(itss);
  1439. for(SAMPLEINDEX smp = 0; smp < itHeader.smpnum; smp++)
  1440. {
  1441. smppos[smp] = static_cast<uint32>(dwPos);
  1442. dwPos += sizeof(ITSample);
  1443. mpt::IO::Write(f, itss);
  1444. }
  1445. // Writing Patterns
  1446. bool needsMptPatSave = false;
  1447. for(PATTERNINDEX pat = 0; pat < itHeader.patnum; pat++)
  1448. {
  1449. uint32 dwPatPos = static_cast<uint32>(dwPos);
  1450. if (!Patterns.IsValidPat(pat)) continue;
  1451. if(Patterns[pat].GetOverrideSignature())
  1452. needsMptPatSave = true;
  1453. // Check for empty pattern
  1454. if(Patterns[pat].GetNumRows() == 64 && Patterns.IsPatternEmpty(pat))
  1455. {
  1456. patpos[pat] = 0;
  1457. continue;
  1458. }
  1459. patpos[pat] = static_cast<uint32>(dwPos);
  1460. // Write pattern header
  1461. ROWINDEX writeRows = mpt::saturate_cast<uint16>(Patterns[pat].GetNumRows());
  1462. uint16 writeSize = 0;
  1463. uint16le patinfo[4];
  1464. patinfo[0] = 0;
  1465. patinfo[1] = static_cast<uint16>(writeRows);
  1466. patinfo[2] = 0;
  1467. patinfo[3] = 0;
  1468. mpt::IO::Write(f, patinfo);
  1469. dwPos += 8;
  1470. struct ChnState { ModCommand lastCmd; uint8 mask = 0xFF; };
  1471. const CHANNELINDEX maxChannels = std::min(specs.channelsMax, GetNumChannels());
  1472. std::vector<ChnState> chnStates(maxChannels);
  1473. // Maximum 7 bytes per cell, plus end of row marker, so this buffer is always large enough to cover one row.
  1474. std::vector<uint8> buf(7 * maxChannels + 1);
  1475. for(ROWINDEX row = 0; row < writeRows; row++)
  1476. {
  1477. uint32 len = 0;
  1478. const ModCommand *m = Patterns[pat].GetpModCommand(row, 0);
  1479. for(CHANNELINDEX ch = 0; ch < maxChannels; ch++, m++)
  1480. {
  1481. // Skip mptm-specific notes.
  1482. if(m->IsPcNote())
  1483. {
  1484. needsMptPatSave = true;
  1485. continue;
  1486. }
  1487. auto &chnState = chnStates[ch];
  1488. uint8 b = 0;
  1489. uint8 command = m->command;
  1490. uint8 param = m->param;
  1491. uint8 vol = 0xFF;
  1492. uint8 note = m->note;
  1493. if (note != NOTE_NONE) b |= 1;
  1494. if (m->IsNote()) note -= NOTE_MIN;
  1495. if (note == NOTE_FADE && GetType() != MOD_TYPE_MPT) note = 0xF6;
  1496. if (m->instr) b |= 2;
  1497. if (m->volcmd != VOLCMD_NONE)
  1498. {
  1499. vol = std::min(m->vol, uint8(9));
  1500. switch(m->volcmd)
  1501. {
  1502. case VOLCMD_VOLUME: vol = std::min(m->vol, uint8(64)); break;
  1503. case VOLCMD_PANNING: vol = std::min(m->vol, uint8(64)) + 128; break;
  1504. case VOLCMD_VOLSLIDEUP: vol += 85; break;
  1505. case VOLCMD_VOLSLIDEDOWN: vol += 95; break;
  1506. case VOLCMD_FINEVOLUP: vol += 65; break;
  1507. case VOLCMD_FINEVOLDOWN: vol += 75; break;
  1508. case VOLCMD_VIBRATODEPTH: vol += 203; break;
  1509. case VOLCMD_TONEPORTAMENTO: vol += 193; break;
  1510. case VOLCMD_PORTADOWN: vol += 105; break;
  1511. case VOLCMD_PORTAUP: vol += 115; break;
  1512. case VOLCMD_VIBRATOSPEED:
  1513. if(command == CMD_NONE)
  1514. {
  1515. // Move unsupported command if possible
  1516. command = CMD_VIBRATO;
  1517. param = std::min(m->vol, uint8(15)) << 4;
  1518. vol = 0xFF;
  1519. } else
  1520. {
  1521. vol = 203;
  1522. }
  1523. break;
  1524. case VOLCMD_OFFSET:
  1525. if(!compatibilityExport)
  1526. vol += 223;
  1527. else
  1528. vol = 0xFF;
  1529. break;
  1530. default: vol = 0xFF;
  1531. }
  1532. }
  1533. if (vol != 0xFF) b |= 4;
  1534. if (command != CMD_NONE)
  1535. {
  1536. S3MSaveConvert(command, param, true, compatibilityExport);
  1537. if (command) b |= 8;
  1538. }
  1539. // Packing information
  1540. if (b)
  1541. {
  1542. // Same note ?
  1543. if (b & 1)
  1544. {
  1545. if ((note == chnState.lastCmd.note) && (chnState.lastCmd.volcmd & 1))
  1546. {
  1547. b &= ~1;
  1548. b |= 0x10;
  1549. } else
  1550. {
  1551. chnState.lastCmd.note = note;
  1552. chnState.lastCmd.volcmd |= 1;
  1553. }
  1554. }
  1555. // Same instrument ?
  1556. if (b & 2)
  1557. {
  1558. if ((m->instr == chnState.lastCmd.instr) && (chnState.lastCmd.volcmd & 2))
  1559. {
  1560. b &= ~2;
  1561. b |= 0x20;
  1562. } else
  1563. {
  1564. chnState.lastCmd.instr = m->instr;
  1565. chnState.lastCmd.volcmd |= 2;
  1566. }
  1567. }
  1568. // Same volume column byte ?
  1569. if (b & 4)
  1570. {
  1571. if ((vol == chnState.lastCmd.vol) && (chnState.lastCmd.volcmd & 4))
  1572. {
  1573. b &= ~4;
  1574. b |= 0x40;
  1575. } else
  1576. {
  1577. chnState.lastCmd.vol = vol;
  1578. chnState.lastCmd.volcmd |= 4;
  1579. }
  1580. }
  1581. // Same command / param ?
  1582. if (b & 8)
  1583. {
  1584. if ((command == chnState.lastCmd.command) && (param == chnState.lastCmd.param) && (chnState.lastCmd.volcmd & 8))
  1585. {
  1586. b &= ~8;
  1587. b |= 0x80;
  1588. } else
  1589. {
  1590. chnState.lastCmd.command = command;
  1591. chnState.lastCmd.param = param;
  1592. chnState.lastCmd.volcmd |= 8;
  1593. }
  1594. }
  1595. if (b != chnState.mask)
  1596. {
  1597. chnState.mask = b;
  1598. buf[len++] = static_cast<uint8>((ch + 1) | IT_bitmask_patternChanEnabled_c);
  1599. buf[len++] = b;
  1600. } else
  1601. {
  1602. buf[len++] = static_cast<uint8>(ch + 1);
  1603. }
  1604. if (b & 1) buf[len++] = note;
  1605. if (b & 2) buf[len++] = m->instr;
  1606. if (b & 4) buf[len++] = vol;
  1607. if (b & 8)
  1608. {
  1609. buf[len++] = command;
  1610. buf[len++] = param;
  1611. }
  1612. }
  1613. }
  1614. buf[len++] = 0;
  1615. if(writeSize > uint16_max - len)
  1616. {
  1617. AddToLog(LogWarning, MPT_UFORMAT("Warning: File format limit was reached. Some pattern data may not get written to file. (pattern {})")(pat));
  1618. break;
  1619. } else
  1620. {
  1621. dwPos += len;
  1622. writeSize += (uint16)len;
  1623. mpt::IO::WriteRaw(f, buf.data(), len);
  1624. }
  1625. }
  1626. mpt::IO::SeekAbsolute(f, dwPatPos);
  1627. patinfo[0] = writeSize;
  1628. mpt::IO::Write(f, patinfo);
  1629. mpt::IO::SeekAbsolute(f, dwPos);
  1630. }
  1631. // Writing Sample Data
  1632. for(SAMPLEINDEX smp = 1; smp <= itHeader.smpnum; smp++)
  1633. {
  1634. const ModSample &sample = Samples[smp];
  1635. #ifdef MODPLUG_TRACKER
  1636. uint32 type = GetType() == MOD_TYPE_IT ? 1 : 4;
  1637. if(compatibilityExport) type = 2;
  1638. bool compress = ((((sample.GetNumChannels() > 1) ? TrackerSettings::Instance().MiscITCompressionStereo : TrackerSettings::Instance().MiscITCompressionMono) & type) != 0);
  1639. #else
  1640. bool compress = false;
  1641. #endif // MODPLUG_TRACKER
  1642. // Old MPT, DUMB and probably other libraries will only consider the IT2.15 compression flag if the header version also indicates IT2.15.
  1643. // MilkyTracker <= 0.90.85 assumes IT2.15 compression with cmwt == 0x215, ignoring the delta flag completely.
  1644. itss.ConvertToIT(sample, GetType(), compress, itHeader.cmwt >= 0x215, GetType() == MOD_TYPE_MPT);
  1645. const bool isExternal = itss.cvt == ITSample::cvtExternalSample;
  1646. mpt::String::WriteBuf(mpt::String::nullTerminated, itss.name) = m_szNames[smp];
  1647. itss.samplepointer = static_cast<uint32>(dwPos);
  1648. if(dwPos > uint32_max)
  1649. {
  1650. // Sample position does not fit into sample pointer!
  1651. AddToLog(LogWarning, MPT_UFORMAT("Cannot save sample {}: File size exceeds 4 GB.")(smp));
  1652. itss.samplepointer = 0;
  1653. itss.length = 0;
  1654. }
  1655. SmpLength smpLength = itss.length; // Possibly truncated to 2^32 samples
  1656. mpt::IO::SeekAbsolute(f, smppos[smp - 1]);
  1657. mpt::IO::Write(f, itss);
  1658. if(dwPos > uint32_max)
  1659. {
  1660. continue;
  1661. }
  1662. // TODO this actually wraps around at 2 GB, so we either need to use the 64-bit seek API or warn earlier!
  1663. mpt::IO::SeekAbsolute(f, dwPos);
  1664. if(!isExternal)
  1665. {
  1666. if(sample.nLength > smpLength && smpLength != 0)
  1667. {
  1668. // Sample length does not fit into IT header!
  1669. AddToLog(LogWarning, MPT_UFORMAT("Truncating sample {}: Length exceeds exceeds 4 gigasamples.")(smp));
  1670. }
  1671. dwPos += itss.GetSampleFormat().WriteSample(f, sample, smpLength);
  1672. } else
  1673. {
  1674. #ifdef MPT_EXTERNAL_SAMPLES
  1675. const std::string filenameU8 = GetSamplePath(smp).AbsolutePathToRelative(filename.GetPath()).ToUTF8();
  1676. const size_t strSize = filenameU8.size();
  1677. size_t intBytes = 0;
  1678. if(mpt::IO::WriteVarInt(f, strSize, &intBytes))
  1679. {
  1680. dwPos += intBytes + strSize;
  1681. mpt::IO::WriteRaw(f, filenameU8.data(), strSize);
  1682. }
  1683. #else
  1684. MPT_UNREFERENCED_PARAMETER(filename);
  1685. #endif // MPT_EXTERNAL_SAMPLES
  1686. }
  1687. }
  1688. //Save hacked-on extra info
  1689. if(!compatibilityExport)
  1690. {
  1691. if(GetNumInstruments())
  1692. {
  1693. SaveExtendedInstrumentProperties(itHeader.insnum, f);
  1694. }
  1695. SaveExtendedSongProperties(f);
  1696. }
  1697. // Updating offsets
  1698. mpt::IO::SeekAbsolute(f, dwHdrPos);
  1699. mpt::IO::Write(f, inspos);
  1700. mpt::IO::Write(f, smppos);
  1701. mpt::IO::Write(f, patpos);
  1702. if(GetType() == MOD_TYPE_IT)
  1703. {
  1704. return true;
  1705. }
  1706. //hack
  1707. //BEGIN: MPT SPECIFIC:
  1708. bool success = true;
  1709. mpt::IO::SeekEnd(f);
  1710. const mpt::IO::Offset MPTStartPos = mpt::IO::TellWrite(f);
  1711. srlztn::SsbWrite ssb(f);
  1712. ssb.BeginWrite("mptm", Version::Current().GetRawVersion());
  1713. if(GetTuneSpecificTunings().GetNumTunings() > 0 || AreNonDefaultTuningsUsed(*this))
  1714. ssb.WriteItem(int8(1), "UTF8Tuning");
  1715. if(GetTuneSpecificTunings().GetNumTunings() > 0)
  1716. ssb.WriteItem(GetTuneSpecificTunings(), "0", &WriteTuningCollection);
  1717. if(AreNonDefaultTuningsUsed(*this))
  1718. ssb.WriteItem(*this, "1", &WriteTuningMap);
  1719. if(Order().NeedsExtraDatafield())
  1720. ssb.WriteItem(Order, "2", &WriteModSequenceOld);
  1721. if(needsMptPatSave)
  1722. ssb.WriteItem(Patterns, FileIdPatterns, &WriteModPatterns);
  1723. ssb.WriteItem(Order, FileIdSequences, &WriteModSequences);
  1724. ssb.FinishWrite();
  1725. if(ssb.GetStatus() & srlztn::SNT_FAILURE)
  1726. {
  1727. AddToLog(LogError, U_("Error occurred in writing MPTM extensions."));
  1728. }
  1729. //Last 4 bytes should tell where the hack mpt things begin.
  1730. if(!f.good())
  1731. {
  1732. f.clear();
  1733. success = false;
  1734. }
  1735. mpt::IO::WriteIntLE<uint32>(f, static_cast<uint32>(MPTStartPos));
  1736. mpt::IO::SeekEnd(f);
  1737. //END : MPT SPECIFIC
  1738. //NO WRITING HERE ANYMORE.
  1739. return success;
  1740. }
  1741. #endif // MODPLUG_NO_FILESAVE
  1742. #ifndef MODPLUG_NO_FILESAVE
  1743. uint32 CSoundFile::SaveMixPlugins(std::ostream *file, bool updatePlugData)
  1744. {
  1745. #ifndef NO_PLUGINS
  1746. uint32 totalSize = 0;
  1747. for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
  1748. {
  1749. const SNDMIXPLUGIN &plugin = m_MixPlugins[i];
  1750. if(plugin.IsValidPlugin())
  1751. {
  1752. uint32 chunkSize = sizeof(SNDMIXPLUGININFO) + 4; // plugininfo+4 (datalen)
  1753. if(plugin.pMixPlugin && updatePlugData)
  1754. {
  1755. plugin.pMixPlugin->SaveAllParameters();
  1756. }
  1757. const uint32 extraDataSize =
  1758. 4 + sizeof(float32) + // 4 for ID and size of dryRatio
  1759. 4 + sizeof(int32); // Default Program
  1760. // For each extra entity, add 4 for ID, plus 4 for size of entity, plus size of entity
  1761. chunkSize += extraDataSize + 4; // +4 is for size field itself
  1762. const uint32 plugDataSize = std::min(mpt::saturate_cast<uint32>(plugin.pluginData.size()), uint32_max - chunkSize);
  1763. chunkSize += plugDataSize;
  1764. if(file)
  1765. {
  1766. std::ostream &f = *file;
  1767. // Chunk ID (= plugin ID)
  1768. char id[4] = { 'F', 'X', '0', '0' };
  1769. if(i >= 100) id[1] = '0' + (i / 100u);
  1770. id[2] += (i / 10u) % 10u;
  1771. id[3] += (i % 10u);
  1772. mpt::IO::WriteRaw(f, id, 4);
  1773. // Write chunk size, plugin info and plugin data chunk
  1774. mpt::IO::WriteIntLE<uint32>(f, chunkSize);
  1775. mpt::IO::Write(f, m_MixPlugins[i].Info);
  1776. mpt::IO::WriteIntLE<uint32>(f, plugDataSize);
  1777. if(plugDataSize)
  1778. {
  1779. mpt::IO::WriteRaw(f, m_MixPlugins[i].pluginData.data(), plugDataSize);
  1780. }
  1781. mpt::IO::WriteIntLE<uint32>(f, extraDataSize);
  1782. // Dry/Wet ratio
  1783. mpt::IO::WriteRaw(f, "DWRT", 4);
  1784. // DWRT chunk does not include a size, so better make sure we always write 4 bytes here.
  1785. static_assert(sizeof(IEEE754binary32LE) == 4);
  1786. mpt::IO::Write(f, IEEE754binary32LE(m_MixPlugins[i].fDryRatio));
  1787. // Default program
  1788. mpt::IO::WriteRaw(f, "PROG", 4);
  1789. // PROG chunk does not include a size, so better make sure we always write 4 bytes here.
  1790. static_assert(sizeof(m_MixPlugins[i].defaultProgram) == sizeof(int32));
  1791. mpt::IO::WriteIntLE<int32>(f, m_MixPlugins[i].defaultProgram);
  1792. // Please, if you add any more chunks here, don't repeat history (see above) and *do* add a size field for your chunk, mmmkay?
  1793. }
  1794. totalSize += chunkSize + 8;
  1795. }
  1796. }
  1797. std::vector<uint32le> chinfo(GetNumChannels());
  1798. uint32 numChInfo = 0;
  1799. for(CHANNELINDEX j = 0; j < GetNumChannels(); j++)
  1800. {
  1801. if((chinfo[j] = ChnSettings[j].nMixPlugin) != 0)
  1802. {
  1803. numChInfo = j + 1;
  1804. }
  1805. }
  1806. if(numChInfo)
  1807. {
  1808. if(file)
  1809. {
  1810. std::ostream &f = *file;
  1811. mpt::IO::WriteRaw(f, "CHFX", 4);
  1812. mpt::IO::WriteIntLE<uint32>(f, numChInfo * 4);
  1813. chinfo.resize(numChInfo);
  1814. mpt::IO::Write(f, chinfo);
  1815. }
  1816. totalSize += numChInfo * 4 + 8;
  1817. }
  1818. return totalSize;
  1819. #else
  1820. MPT_UNREFERENCED_PARAMETER(file);
  1821. MPT_UNREFERENCED_PARAMETER(updatePlugData);
  1822. return 0;
  1823. #endif // NO_PLUGINS
  1824. }
  1825. #endif // MODPLUG_NO_FILESAVE
  1826. bool CSoundFile::LoadMixPlugins(FileReader &file)
  1827. {
  1828. bool isBeRoTracker = false;
  1829. while(file.CanRead(9))
  1830. {
  1831. char code[4];
  1832. file.ReadArray(code);
  1833. const uint32 chunkSize = file.ReadUint32LE();
  1834. if(!memcmp(code, "IMPI", 4) // IT instrument, we definitely read too far
  1835. || !memcmp(code, "IMPS", 4) // IT sample, ditto
  1836. || !memcmp(code, "XTPM", 4) // Instrument extensions, ditto
  1837. || !memcmp(code, "STPM", 4) // Song extensions, ditto
  1838. || !file.CanRead(chunkSize))
  1839. {
  1840. file.SkipBack(8);
  1841. return isBeRoTracker;
  1842. }
  1843. FileReader chunk = file.ReadChunk(chunkSize);
  1844. // Channel FX
  1845. if(!memcmp(code, "CHFX", 4))
  1846. {
  1847. for(auto &chn : ChnSettings)
  1848. {
  1849. chn.nMixPlugin = static_cast<PLUGINDEX>(chunk.ReadUint32LE());
  1850. }
  1851. #ifndef NO_PLUGINS
  1852. }
  1853. // Plugin Data FX00, ... FX99, F100, ... F255
  1854. #define MPT_ISDIGIT(x) (code[(x)] >= '0' && code[(x)] <= '9')
  1855. else if(code[0] == 'F' && (code[1] == 'X' || MPT_ISDIGIT(1)) && MPT_ISDIGIT(2) && MPT_ISDIGIT(3))
  1856. #undef MPT_ISDIGIT
  1857. {
  1858. PLUGINDEX plug = (code[2] - '0') * 10 + (code[3] - '0'); //calculate plug-in number.
  1859. if(code[1] != 'X') plug += (code[1] - '0') * 100;
  1860. if(plug < MAX_MIXPLUGINS)
  1861. {
  1862. ReadMixPluginChunk(chunk, m_MixPlugins[plug]);
  1863. }
  1864. #endif // NO_PLUGINS
  1865. } else if(!memcmp(code, "MODU", 4))
  1866. {
  1867. isBeRoTracker = true;
  1868. m_dwLastSavedWithVersion = Version(); // Reset MPT detection for old files that have a similar fingerprint
  1869. }
  1870. }
  1871. return isBeRoTracker;
  1872. }
  1873. #ifndef NO_PLUGINS
  1874. void CSoundFile::ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin)
  1875. {
  1876. // MPT's standard plugin data. Size not specified in file.. grrr..
  1877. file.ReadStruct(plugin.Info);
  1878. mpt::String::SetNullTerminator(plugin.Info.szName.buf);
  1879. mpt::String::SetNullTerminator(plugin.Info.szLibraryName.buf);
  1880. plugin.editorX = plugin.editorY = int32_min;
  1881. // Plugin user data
  1882. FileReader pluginDataChunk = file.ReadChunk(file.ReadUint32LE());
  1883. plugin.pluginData.resize(mpt::saturate_cast<size_t>(pluginDataChunk.BytesLeft()));
  1884. pluginDataChunk.ReadRaw(mpt::as_span(plugin.pluginData));
  1885. if(FileReader modularData = file.ReadChunk(file.ReadUint32LE()); modularData.IsValid())
  1886. {
  1887. while(modularData.CanRead(5))
  1888. {
  1889. // do we recognize this chunk?
  1890. char code[4];
  1891. modularData.ReadArray(code);
  1892. uint32 dataSize = 0;
  1893. if(!memcmp(code, "DWRT", 4) || !memcmp(code, "PROG", 4))
  1894. {
  1895. // Legacy system with fixed size chunks
  1896. dataSize = 4;
  1897. } else
  1898. {
  1899. dataSize = modularData.ReadUint32LE();
  1900. }
  1901. FileReader dataChunk = modularData.ReadChunk(dataSize);
  1902. if(!memcmp(code, "DWRT", 4))
  1903. {
  1904. plugin.fDryRatio = std::clamp(dataChunk.ReadFloatLE(), 0.0f, 1.0f);
  1905. if(!std::isnormal(plugin.fDryRatio))
  1906. plugin.fDryRatio = 0.0f;
  1907. } else if(!memcmp(code, "PROG", 4))
  1908. {
  1909. plugin.defaultProgram = dataChunk.ReadUint32LE();
  1910. } else if(!memcmp(code, "MCRO", 4))
  1911. {
  1912. // Read plugin-specific macros
  1913. //dataChunk.ReadStructPartial(plugin.macros, dataChunk.GetLength());
  1914. }
  1915. }
  1916. }
  1917. }
  1918. #endif // NO_PLUGINS
  1919. #ifndef MODPLUG_NO_FILESAVE
  1920. void CSoundFile::SaveExtendedSongProperties(std::ostream &f) const
  1921. {
  1922. const CModSpecifications &specs = GetModSpecifications();
  1923. // Extra song data - Yet Another Hack.
  1924. mpt::IO::WriteIntLE<uint32>(f, MagicBE("MPTS"));
  1925. #define WRITEMODULARHEADER(code, fsize) \
  1926. { \
  1927. mpt::IO::WriteIntLE<uint32>(f, code); \
  1928. MPT_ASSERT(mpt::in_range<uint16>(fsize)); \
  1929. const uint16 _size = fsize; \
  1930. mpt::IO::WriteIntLE<uint16>(f, _size); \
  1931. }
  1932. #define WRITEMODULAR(code, field) \
  1933. { \
  1934. WRITEMODULARHEADER(code, sizeof(field)) \
  1935. mpt::IO::WriteIntLE(f, field); \
  1936. }
  1937. if(m_nDefaultTempo.GetInt() > 255)
  1938. {
  1939. uint32 tempo = m_nDefaultTempo.GetInt();
  1940. WRITEMODULAR(MagicBE("DT.."), tempo);
  1941. }
  1942. if(m_nDefaultTempo.GetFract() != 0 && specs.hasFractionalTempo)
  1943. {
  1944. uint32 tempo = m_nDefaultTempo.GetFract();
  1945. WRITEMODULAR(MagicLE("DTFR"), tempo);
  1946. }
  1947. if(m_nDefaultRowsPerBeat > 255 || m_nDefaultRowsPerMeasure > 255 || GetType() == MOD_TYPE_XM)
  1948. {
  1949. WRITEMODULAR(MagicBE("RPB."), m_nDefaultRowsPerBeat);
  1950. WRITEMODULAR(MagicBE("RPM."), m_nDefaultRowsPerMeasure);
  1951. }
  1952. if(GetType() != MOD_TYPE_XM)
  1953. {
  1954. WRITEMODULAR(MagicBE("C..."), m_nChannels);
  1955. }
  1956. if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && GetNumChannels() > 64)
  1957. {
  1958. // IT header has only room for 64 channels. Save the settings that do not fit to the header here as an extension.
  1959. WRITEMODULARHEADER(MagicBE("ChnS"), (GetNumChannels() - 64) * 2);
  1960. for(CHANNELINDEX chn = 64; chn < GetNumChannels(); chn++)
  1961. {
  1962. uint8 panvol[2];
  1963. panvol[0] = (uint8)(ChnSettings[chn].nPan >> 2);
  1964. if (ChnSettings[chn].dwFlags[CHN_SURROUND]) panvol[0] = 100;
  1965. if (ChnSettings[chn].dwFlags[CHN_MUTE]) panvol[0] |= 0x80;
  1966. panvol[1] = (uint8)ChnSettings[chn].nVolume;
  1967. mpt::IO::Write(f, panvol);
  1968. }
  1969. }
  1970. {
  1971. WRITEMODULARHEADER(MagicBE("TM.."), 1);
  1972. uint8 mode = static_cast<uint8>(m_nTempoMode);
  1973. mpt::IO::WriteIntLE(f, mode);
  1974. }
  1975. const int32 tmpMixLevels = static_cast<int32>(m_nMixLevels);
  1976. WRITEMODULAR(MagicBE("PMM."), tmpMixLevels);
  1977. if(m_dwCreatedWithVersion)
  1978. {
  1979. WRITEMODULAR(MagicBE("CWV."), m_dwCreatedWithVersion.GetRawVersion());
  1980. }
  1981. WRITEMODULAR(MagicBE("LSWV"), Version::Current().GetRawVersion());
  1982. WRITEMODULAR(MagicBE("SPA."), m_nSamplePreAmp);
  1983. WRITEMODULAR(MagicBE("VSTV"), m_nVSTiVolume);
  1984. if(GetType() == MOD_TYPE_XM && m_nDefaultGlobalVolume != MAX_GLOBAL_VOLUME)
  1985. {
  1986. WRITEMODULAR(MagicBE("DGV."), m_nDefaultGlobalVolume);
  1987. }
  1988. if(GetType() != MOD_TYPE_XM && Order().GetRestartPos() != 0)
  1989. {
  1990. WRITEMODULAR(MagicBE("RP.."), Order().GetRestartPos());
  1991. }
  1992. if(m_nResampling != SRCMODE_DEFAULT && specs.hasDefaultResampling)
  1993. {
  1994. WRITEMODULAR(MagicLE("RSMP"), static_cast<uint32>(m_nResampling));
  1995. }
  1996. // Sample cues
  1997. if(GetType() == MOD_TYPE_MPT)
  1998. {
  1999. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
  2000. {
  2001. const ModSample &sample = Samples[smp];
  2002. if(sample.nLength && sample.HasCustomCuePoints())
  2003. {
  2004. // Write one chunk for every sample.
  2005. // Rationale: chunks are limited to 65536 bytes, which can easily be reached
  2006. // with the amount of samples that OpenMPT supports.
  2007. WRITEMODULARHEADER(MagicLE("CUES"), static_cast<uint16>(2 + std::size(sample.cues) * 4));
  2008. mpt::IO::WriteIntLE<uint16>(f, smp);
  2009. for(auto cue : sample.cues)
  2010. {
  2011. mpt::IO::WriteIntLE<uint32>(f, cue);
  2012. }
  2013. }
  2014. }
  2015. }
  2016. // Tempo Swing Factors
  2017. if(!m_tempoSwing.empty())
  2018. {
  2019. std::ostringstream oStrm;
  2020. TempoSwing::Serialize(oStrm, m_tempoSwing);
  2021. std::string data = oStrm.str();
  2022. uint16 length = mpt::saturate_cast<uint16>(data.size());
  2023. WRITEMODULARHEADER(MagicLE("SWNG"), length);
  2024. mpt::IO::WriteRaw(f, data.data(), length);
  2025. }
  2026. // Playback compatibility flags
  2027. {
  2028. uint8 bits[(kMaxPlayBehaviours + 7) / 8u];
  2029. MemsetZero(bits);
  2030. size_t maxBit = 0;
  2031. for(size_t i = 0; i < kMaxPlayBehaviours; i++)
  2032. {
  2033. if(m_playBehaviour[i])
  2034. {
  2035. bits[i >> 3] |= 1 << (i & 0x07);
  2036. maxBit = i + 8;
  2037. }
  2038. }
  2039. uint16 numBytes = static_cast<uint16>(maxBit / 8u);
  2040. WRITEMODULARHEADER(MagicBE("MSF."), numBytes);
  2041. mpt::IO::WriteRaw(f, bits, numBytes);
  2042. }
  2043. if(!m_songArtist.empty() && specs.hasArtistName)
  2044. {
  2045. std::string songArtistU8 = mpt::ToCharset(mpt::Charset::UTF8, m_songArtist);
  2046. uint16 length = mpt::saturate_cast<uint16>(songArtistU8.length());
  2047. WRITEMODULARHEADER(MagicLE("AUTH"), length);
  2048. mpt::IO::WriteRaw(f, songArtistU8.c_str(), length);
  2049. }
  2050. #ifdef MODPLUG_TRACKER
  2051. // MIDI mapping directives
  2052. if(GetMIDIMapper().GetCount() > 0)
  2053. {
  2054. const size_t objectsize = GetMIDIMapper().Serialize();
  2055. if(!mpt::in_range<uint16>(objectsize))
  2056. {
  2057. AddToLog(LogWarning, U_("Too many MIDI Mapping directives to save; data won't be written."));
  2058. } else
  2059. {
  2060. WRITEMODULARHEADER(MagicBE("MIMA"), static_cast<uint16>(objectsize));
  2061. GetMIDIMapper().Serialize(&f);
  2062. }
  2063. }
  2064. // Channel colors
  2065. {
  2066. CHANNELINDEX numChannels = 0;
  2067. for(CHANNELINDEX i = 0; i < m_nChannels; i++)
  2068. {
  2069. if(ChnSettings[i].color != ModChannelSettings::INVALID_COLOR)
  2070. {
  2071. numChannels = i + 1;
  2072. }
  2073. }
  2074. if(numChannels > 0)
  2075. {
  2076. WRITEMODULARHEADER(MagicLE("CCOL"), numChannels * 4);
  2077. for(CHANNELINDEX i = 0; i < numChannels; i++)
  2078. {
  2079. uint32 color = ChnSettings[i].color;
  2080. if(color != ModChannelSettings::INVALID_COLOR)
  2081. color &= 0x00FFFFFF;
  2082. std::array<uint8, 4> rgb{static_cast<uint8>(color), static_cast<uint8>(color >> 8), static_cast<uint8>(color >> 16), static_cast<uint8>(color >> 24)};
  2083. mpt::IO::Write(f, rgb);
  2084. }
  2085. }
  2086. }
  2087. #endif
  2088. #undef WRITEMODULAR
  2089. #undef WRITEMODULARHEADER
  2090. return;
  2091. }
  2092. #endif // MODPLUG_NO_FILESAVE
  2093. template<typename T>
  2094. void ReadField(FileReader &chunk, std::size_t size, T &field)
  2095. {
  2096. field = chunk.ReadSizedIntLE<T>(size);
  2097. }
  2098. template<typename T>
  2099. void ReadFieldCast(FileReader &chunk, std::size_t size, T &field)
  2100. {
  2101. static_assert(sizeof(T) <= sizeof(int32));
  2102. field = static_cast<T>(chunk.ReadSizedIntLE<int32>(size));
  2103. }
  2104. void CSoundFile::LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool *pInterpretMptMade)
  2105. {
  2106. if(!file.ReadMagic("STPM")) // 'MPTS'
  2107. {
  2108. return;
  2109. }
  2110. // Found MPTS, interpret the file MPT made.
  2111. if(pInterpretMptMade != nullptr)
  2112. *pInterpretMptMade = true;
  2113. // HACK: Reset mod flags to default values here, as they are not always written.
  2114. m_playBehaviour.reset();
  2115. while(file.CanRead(7))
  2116. {
  2117. const uint32 code = file.ReadUint32LE();
  2118. const uint16 size = file.ReadUint16LE();
  2119. // Start of MPTM extensions, non-ASCII ID or truncated field
  2120. if(code == MagicLE("228\x04"))
  2121. {
  2122. file.SkipBack(6);
  2123. break;
  2124. } else if((code & 0x80808080) || !(code & 0x60606060) || !file.CanRead(size))
  2125. {
  2126. break;
  2127. }
  2128. FileReader chunk = file.ReadChunk(size);
  2129. switch (code) // interpret field code
  2130. {
  2131. case MagicBE("DT.."): { uint32 tempo; ReadField(chunk, size, tempo); m_nDefaultTempo.Set(tempo, m_nDefaultTempo.GetFract()); break; }
  2132. case MagicLE("DTFR"): { uint32 tempoFract; ReadField(chunk, size, tempoFract); m_nDefaultTempo.Set(m_nDefaultTempo.GetInt(), tempoFract); break; }
  2133. case MagicBE("RPB."): ReadField(chunk, size, m_nDefaultRowsPerBeat); break;
  2134. case MagicBE("RPM."): ReadField(chunk, size, m_nDefaultRowsPerMeasure); break;
  2135. // FIXME: If there are only PC events on the last few channels in an MPTM MO3, they won't be imported!
  2136. case MagicBE("C..."): if(!ignoreChannelCount) { CHANNELINDEX chn = 0; ReadField(chunk, size, chn); m_nChannels = Clamp(chn, m_nChannels, MAX_BASECHANNELS); } break;
  2137. case MagicBE("TM.."): ReadFieldCast(chunk, size, m_nTempoMode); break;
  2138. case MagicBE("PMM."): ReadFieldCast(chunk, size, m_nMixLevels); break;
  2139. case MagicBE("CWV."): { uint32 ver = 0; ReadField(chunk, size, ver); m_dwCreatedWithVersion = Version(ver); break; }
  2140. case MagicBE("LSWV"): { uint32 ver = 0; ReadField(chunk, size, ver); if(ver != 0) { m_dwLastSavedWithVersion = Version(ver); } break; }
  2141. case MagicBE("SPA."): ReadField(chunk, size, m_nSamplePreAmp); break;
  2142. case MagicBE("VSTV"): ReadField(chunk, size, m_nVSTiVolume); break;
  2143. case MagicBE("DGV."): ReadField(chunk, size, m_nDefaultGlobalVolume); break;
  2144. case MagicBE("RP.."): if(GetType() != MOD_TYPE_XM) { ORDERINDEX restartPos; ReadField(chunk, size, restartPos); Order().SetRestartPos(restartPos); } break;
  2145. case MagicLE("RSMP"):
  2146. ReadFieldCast(chunk, size, m_nResampling);
  2147. if(!Resampling::IsKnownMode(m_nResampling)) m_nResampling = SRCMODE_DEFAULT;
  2148. break;
  2149. #ifdef MODPLUG_TRACKER
  2150. case MagicBE("MIMA"): GetMIDIMapper().Deserialize(chunk); break;
  2151. case MagicLE("CCOL"):
  2152. // Channel colors
  2153. {
  2154. const CHANNELINDEX numChannels = std::min(MAX_BASECHANNELS, static_cast<CHANNELINDEX>(size / 4u));
  2155. for(CHANNELINDEX i = 0; i < numChannels; i++)
  2156. {
  2157. auto rgb = chunk.ReadArray<uint8, 4>();
  2158. if(rgb[3])
  2159. ChnSettings[i].color = ModChannelSettings::INVALID_COLOR;
  2160. else
  2161. ChnSettings[i].color = rgb[0] | (rgb[1] << 8) | (rgb[2] << 16);
  2162. }
  2163. }
  2164. break;
  2165. #endif
  2166. case MagicLE("AUTH"):
  2167. {
  2168. std::string artist;
  2169. chunk.ReadString<mpt::String::spacePadded>(artist, chunk.GetLength());
  2170. m_songArtist = mpt::ToUnicode(mpt::Charset::UTF8, artist);
  2171. }
  2172. break;
  2173. case MagicBE("ChnS"):
  2174. // Channel settings for channels 65+
  2175. if(size <= (MAX_BASECHANNELS - 64) * 2 && (size % 2u) == 0)
  2176. {
  2177. static_assert(mpt::array_size<decltype(ChnSettings)>::size >= 64);
  2178. const CHANNELINDEX loopLimit = std::min(uint16(64 + size / 2), uint16(std::size(ChnSettings)));
  2179. for(CHANNELINDEX chn = 64; chn < loopLimit; chn++)
  2180. {
  2181. auto [pan, vol] = chunk.ReadArray<uint8, 2>();
  2182. if(pan != 0xFF)
  2183. {
  2184. ChnSettings[chn].nVolume = vol;
  2185. ChnSettings[chn].nPan = 128;
  2186. ChnSettings[chn].dwFlags.reset();
  2187. if(pan & 0x80) ChnSettings[chn].dwFlags.set(CHN_MUTE);
  2188. pan &= 0x7F;
  2189. if(pan <= 64) ChnSettings[chn].nPan = pan << 2;
  2190. if(pan == 100) ChnSettings[chn].dwFlags.set(CHN_SURROUND);
  2191. }
  2192. }
  2193. }
  2194. break;
  2195. case MagicLE("CUES"):
  2196. // Sample cues
  2197. if(size > 2)
  2198. {
  2199. SAMPLEINDEX smp = chunk.ReadUint16LE();
  2200. if(smp > 0 && smp <= GetNumSamples())
  2201. {
  2202. ModSample &sample = Samples[smp];
  2203. for(auto &cue : sample.cues)
  2204. {
  2205. if(chunk.CanRead(4))
  2206. cue = chunk.ReadUint32LE();
  2207. else
  2208. cue = MAX_SAMPLE_LENGTH;
  2209. }
  2210. }
  2211. }
  2212. break;
  2213. case MagicLE("SWNG"):
  2214. // Tempo Swing Factors
  2215. if(size > 2)
  2216. {
  2217. std::istringstream iStrm(mpt::buffer_cast<std::string>(chunk.ReadRawDataAsByteVector()));
  2218. TempoSwing::Deserialize(iStrm, m_tempoSwing, chunk.GetLength());
  2219. }
  2220. break;
  2221. case MagicBE("MSF."):
  2222. // Playback compatibility flags
  2223. {
  2224. size_t bit = 0;
  2225. m_playBehaviour.reset();
  2226. while(chunk.CanRead(1) && bit < m_playBehaviour.size())
  2227. {
  2228. uint8 b = chunk.ReadUint8();
  2229. for(uint8 i = 0; i < 8; i++, bit++)
  2230. {
  2231. if((b & (1 << i)) && bit < m_playBehaviour.size())
  2232. {
  2233. m_playBehaviour.set(bit);
  2234. }
  2235. }
  2236. }
  2237. }
  2238. break;
  2239. }
  2240. }
  2241. // Validate read values.
  2242. Limit(m_nDefaultTempo, GetModSpecifications().GetTempoMin(), GetModSpecifications().GetTempoMax());
  2243. if(m_nTempoMode >= TempoMode::NumModes)
  2244. m_nTempoMode = TempoMode::Classic;
  2245. if(m_nMixLevels >= MixLevels::NumMixLevels)
  2246. m_nMixLevels = MixLevels::Original;
  2247. //m_dwCreatedWithVersion
  2248. //m_dwLastSavedWithVersion
  2249. //m_nSamplePreAmp
  2250. //m_nVSTiVolume
  2251. //m_nDefaultGlobalVolume
  2252. LimitMax(m_nDefaultGlobalVolume, MAX_GLOBAL_VOLUME);
  2253. //m_nRestartPos
  2254. //m_ModFlags
  2255. LimitMax(m_nDefaultRowsPerBeat, MAX_ROWS_PER_BEAT);
  2256. LimitMax(m_nDefaultRowsPerMeasure, MAX_ROWS_PER_BEAT);
  2257. }
  2258. OPENMPT_NAMESPACE_END