1
0

ITTools.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /*
  2. * ITTools.cpp
  3. * -----------
  4. * Purpose: Definition of IT file structures and helper functions
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "Loaders.h"
  11. #include "ITTools.h"
  12. #include "Tables.h"
  13. #include "../common/mptStringBuffer.h"
  14. #include "../common/version.h"
  15. OPENMPT_NAMESPACE_BEGIN
  16. // Convert OpenMPT's internal envelope format into an IT/MPTM envelope.
  17. void ITEnvelope::ConvertToIT(const InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 envDefault)
  18. {
  19. // Envelope Flags
  20. if(mptEnv.dwFlags[ENV_ENABLED]) flags |= ITEnvelope::envEnabled;
  21. if(mptEnv.dwFlags[ENV_LOOP]) flags |= ITEnvelope::envLoop;
  22. if(mptEnv.dwFlags[ENV_SUSTAIN]) flags |= ITEnvelope::envSustain;
  23. if(mptEnv.dwFlags[ENV_CARRY]) flags |= ITEnvelope::envCarry;
  24. // Nodes and Loops
  25. num = (uint8)std::min(mptEnv.size(), uint32(25));
  26. lpb = (uint8)mptEnv.nLoopStart;
  27. lpe = (uint8)mptEnv.nLoopEnd;
  28. slb = (uint8)mptEnv.nSustainStart;
  29. sle = (uint8)mptEnv.nSustainEnd;
  30. // Envelope Data
  31. MemsetZero(data);
  32. if(!mptEnv.empty())
  33. {
  34. // Attention: Full MPTM envelope is stored in extended instrument properties
  35. for(uint32 ev = 0; ev < num; ev++)
  36. {
  37. data[ev].value = static_cast<int8>(mptEnv[ev].value) - envOffset;
  38. data[ev].tick = mptEnv[ev].tick;
  39. }
  40. } else
  41. {
  42. // Fix non-existing envelopes so that they can still be edited in Impulse Tracker.
  43. num = 2;
  44. data[0].value = data[1].value = envDefault - envOffset;
  45. data[1].tick = 10;
  46. }
  47. }
  48. // Convert IT/MPTM envelope data into OpenMPT's internal envelope format - To be used by ITInstrToMPT()
  49. void ITEnvelope::ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envOffset, uint8 maxNodes) const
  50. {
  51. // Envelope Flags
  52. mptEnv.dwFlags.set(ENV_ENABLED, (flags & ITEnvelope::envEnabled) != 0);
  53. mptEnv.dwFlags.set(ENV_LOOP, (flags & ITEnvelope::envLoop) != 0);
  54. mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & ITEnvelope::envSustain) != 0);
  55. mptEnv.dwFlags.set(ENV_CARRY, (flags & ITEnvelope::envCarry) != 0);
  56. // Nodes and Loops
  57. mptEnv.resize(std::min(num, maxNodes));
  58. mptEnv.nLoopStart = std::min(lpb, maxNodes);
  59. mptEnv.nLoopEnd = Clamp(lpe, mptEnv.nLoopStart, maxNodes);
  60. mptEnv.nSustainStart = std::min(slb, maxNodes);
  61. mptEnv.nSustainEnd = Clamp(sle, mptEnv.nSustainStart, maxNodes);
  62. // Envelope Data
  63. // Attention: Full MPTM envelope is stored in extended instrument properties
  64. for(uint32 ev = 0; ev < std::min(uint8(25), num); ev++)
  65. {
  66. mptEnv[ev].value = Clamp<int8, int8>(data[ev].value + envOffset, 0, 64);
  67. mptEnv[ev].tick = data[ev].tick;
  68. if(ev > 0 && mptEnv[ev].tick < mptEnv[ev - 1].tick && !(mptEnv[ev].tick & 0xFF00))
  69. {
  70. // Fix broken envelopes... Instruments 2 and 3 in NoGap.it by Werewolf have envelope points where the high byte of envelope nodes is missing.
  71. // NoGap.it was saved with MPT 1.07 - 1.09, which *normally* doesn't do this in IT files.
  72. // However... It turns out that MPT 1.07 omitted the high byte of envelope nodes when saving an XI instrument file, and it looks like
  73. // Instrument 2 and 3 in NoGap.it were loaded from XI files.
  74. mptEnv[ev].tick |= mptEnv[ev - 1].tick & 0xFF00;
  75. if(mptEnv[ev].tick < mptEnv[ev - 1].tick)
  76. mptEnv[ev].tick += 0x100;
  77. }
  78. }
  79. }
  80. // Convert an ITOldInstrument to OpenMPT's internal instrument representation.
  81. void ITOldInstrument::ConvertToMPT(ModInstrument &mptIns) const
  82. {
  83. // Header
  84. if(memcmp(id, "IMPI", 4))
  85. {
  86. return;
  87. }
  88. mptIns.name = mpt::String::ReadBuf(mpt::String::spacePadded, name);
  89. mptIns.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename);
  90. // Volume / Panning
  91. mptIns.nFadeOut = fadeout << 6;
  92. mptIns.nGlobalVol = 64;
  93. mptIns.nPan = 128;
  94. // NNA Stuff
  95. mptIns.nNNA = static_cast<NewNoteAction>(nna.get());
  96. mptIns.nDCT = static_cast<DuplicateCheckType>(dnc.get());
  97. // Sample Map
  98. for(size_t i = 0; i < 120; i++)
  99. {
  100. uint8 note = keyboard[i * 2];
  101. SAMPLEINDEX ins = keyboard[i * 2 + 1];
  102. if(ins < MAX_SAMPLES)
  103. {
  104. mptIns.Keyboard[i] = ins;
  105. }
  106. if(note < 120)
  107. {
  108. mptIns.NoteMap[i] = note + 1u;
  109. } else
  110. {
  111. mptIns.NoteMap[i] = static_cast<uint8>(i + 1);
  112. }
  113. }
  114. // Volume Envelope Flags
  115. mptIns.VolEnv.dwFlags.set(ENV_ENABLED, (flags & ITOldInstrument::envEnabled) != 0);
  116. mptIns.VolEnv.dwFlags.set(ENV_LOOP, (flags & ITOldInstrument::envLoop) != 0);
  117. mptIns.VolEnv.dwFlags.set(ENV_SUSTAIN, (flags & ITOldInstrument::envSustain) != 0);
  118. // Volume Envelope Loops
  119. mptIns.VolEnv.nLoopStart = vls;
  120. mptIns.VolEnv.nLoopEnd = vle;
  121. mptIns.VolEnv.nSustainStart = sls;
  122. mptIns.VolEnv.nSustainEnd = sle;
  123. mptIns.VolEnv.resize(25);
  124. // Volume Envelope Data
  125. for(uint32 i = 0; i < 25; i++)
  126. {
  127. if((mptIns.VolEnv[i].tick = nodes[i * 2]) == 0xFF)
  128. {
  129. mptIns.VolEnv.resize(i);
  130. break;
  131. }
  132. mptIns.VolEnv[i].value = nodes[i * 2 + 1];
  133. }
  134. if(std::max(mptIns.VolEnv.nLoopStart, mptIns.VolEnv.nLoopEnd) >= mptIns.VolEnv.size()) mptIns.VolEnv.dwFlags.reset(ENV_LOOP);
  135. if(std::max(mptIns.VolEnv.nSustainStart, mptIns.VolEnv.nSustainEnd) >= mptIns.VolEnv.size()) mptIns.VolEnv.dwFlags.reset(ENV_SUSTAIN);
  136. }
  137. // Convert OpenMPT's internal instrument representation to an ITInstrument.
  138. uint32 ITInstrument::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile)
  139. {
  140. MemsetZero(*this);
  141. // Header
  142. memcpy(id, "IMPI", 4);
  143. trkvers = 0x5000 | static_cast<uint16>(Version::Current().GetRawVersion() >> 16);
  144. mpt::String::WriteBuf(mpt::String::nullTerminated, filename) = mptIns.filename;
  145. mpt::String::WriteBuf(mpt::String::nullTerminated, name) = mptIns.name;
  146. // Volume / Panning
  147. fadeout = static_cast<uint16>(std::min(mptIns.nFadeOut >> 5, uint32(256)));
  148. gbv = static_cast<uint8>(std::min(mptIns.nGlobalVol * 2u, uint32(128)));
  149. dfp = static_cast<uint8>(std::min(mptIns.nPan / 4u, uint32(64)));
  150. if(!mptIns.dwFlags[INS_SETPANNING]) dfp |= ITInstrument::ignorePanning;
  151. // Random Variation
  152. rv = std::min(mptIns.nVolSwing, uint8(100));
  153. rp = std::min(mptIns.nPanSwing, uint8(64));
  154. // NNA Stuff
  155. nna = static_cast<uint8>(mptIns.nNNA);
  156. dct = static_cast<uint8>((mptIns.nDCT < DuplicateCheckType::Plugin || !compatExport) ? mptIns.nDCT : DuplicateCheckType::None);
  157. dca = static_cast<uint8>(mptIns.nDNA);
  158. // Pitch / Pan Separation
  159. pps = mptIns.nPPS;
  160. ppc = mptIns.nPPC;
  161. // Filter Stuff
  162. ifc = mptIns.GetCutoff() | (mptIns.IsCutoffEnabled() ? ITInstrument::enableCutoff : 0x00);
  163. ifr = mptIns.GetResonance() | (mptIns.IsResonanceEnabled() ? ITInstrument::enableResonance : 0x00);
  164. // MIDI Setup
  165. if(mptIns.nMidiProgram > 0)
  166. mpr = mptIns.nMidiProgram - 1u;
  167. else
  168. mpr = 0xFF;
  169. if(mptIns.wMidiBank > 0)
  170. {
  171. mbank[0] = static_cast<uint8>((mptIns.wMidiBank - 1) & 0x7F);
  172. mbank[1] = static_cast<uint8>((mptIns.wMidiBank - 1) >> 7);
  173. } else
  174. {
  175. mbank[0] = 0xFF;
  176. mbank[1] = 0xFF;
  177. }
  178. if(mptIns.nMidiChannel != MidiNoChannel || mptIns.nMixPlug == 0 || mptIns.nMixPlug > 127 || compatExport)
  179. {
  180. // Default. Prefer MIDI channel over mixplug to keep the semantics intact.
  181. mch = mptIns.nMidiChannel;
  182. } else
  183. {
  184. // Keep compatibility with MPT 1.16's instrument format if possible, as XMPlay / BASS also uses this.
  185. mch = mptIns.nMixPlug + 128;
  186. }
  187. // Sample Map
  188. nos = 0; // Only really relevant for ITI files
  189. std::vector<bool> smpCount(sndFile.GetNumSamples(), false);
  190. for(int i = 0; i < 120; i++)
  191. {
  192. keyboard[i * 2] = (mptIns.NoteMap[i] >= NOTE_MIN && mptIns.NoteMap[i] <= NOTE_MAX) ? (mptIns.NoteMap[i] - NOTE_MIN) : static_cast<uint8>(i);
  193. const SAMPLEINDEX smp = mptIns.Keyboard[i];
  194. if(smp < MAX_SAMPLES && smp < 256)
  195. {
  196. keyboard[i * 2 + 1] = static_cast<uint8>(smp);
  197. if(smp && smp <= sndFile.GetNumSamples() && !smpCount[smp - 1])
  198. {
  199. // We haven't considered this sample yet. Update number of samples.
  200. smpCount[smp - 1] = true;
  201. nos++;
  202. }
  203. }
  204. }
  205. // Writing Volume envelope
  206. volenv.ConvertToIT(mptIns.VolEnv, 0, 64);
  207. // Writing Panning envelope
  208. panenv.ConvertToIT(mptIns.PanEnv, 32, 32);
  209. // Writing Pitch Envelope
  210. pitchenv.ConvertToIT(mptIns.PitchEnv, 32, 32);
  211. if(mptIns.PitchEnv.dwFlags[ENV_FILTER]) pitchenv.flags |= ITEnvelope::envFilter;
  212. return sizeof(ITInstrument);
  213. }
  214. // Convert an ITInstrument to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read.
  215. uint32 ITInstrument::ConvertToMPT(ModInstrument &mptIns, MODTYPE modFormat) const
  216. {
  217. if(memcmp(id, "IMPI", 4))
  218. {
  219. return 0;
  220. }
  221. mptIns.name = mpt::String::ReadBuf(mpt::String::spacePadded, name);
  222. mptIns.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename);
  223. // Volume / Panning
  224. mptIns.nFadeOut = fadeout << 5;
  225. mptIns.nGlobalVol = gbv / 2;
  226. LimitMax(mptIns.nGlobalVol, 64u);
  227. mptIns.nPan = (dfp & 0x7F) * 4;
  228. if(mptIns.nPan > 256) mptIns.nPan = 128;
  229. mptIns.dwFlags.set(INS_SETPANNING, !(dfp & ITInstrument::ignorePanning));
  230. // Random Variation
  231. mptIns.nVolSwing = std::min(static_cast<uint8>(rv), uint8(100));
  232. mptIns.nPanSwing = std::min(static_cast<uint8>(rp), uint8(64));
  233. // NNA Stuff
  234. mptIns.nNNA = static_cast<NewNoteAction>(nna.get());
  235. mptIns.nDCT = static_cast<DuplicateCheckType>(dct.get());
  236. mptIns.nDNA = static_cast<DuplicateNoteAction>(dca.get());
  237. // Pitch / Pan Separation
  238. mptIns.nPPS = pps;
  239. mptIns.nPPC = ppc;
  240. // Filter Stuff
  241. mptIns.SetCutoff(ifc & 0x7F, (ifc & ITInstrument::enableCutoff) != 0);
  242. mptIns.SetResonance(ifr & 0x7F, (ifr & ITInstrument::enableResonance) != 0);
  243. // MIDI Setup
  244. // MPT used to have a slightly different encoding of MIDI program and banks which we are trying to fix here.
  245. // Impulse Tracker / Schism Tracker will set trkvers to 0 in IT files,
  246. // and we won't care about correctly importing MIDI programs and banks in ITI files.
  247. // Chibi Tracker sets trkvers to 0x214, but always writes mpr=mbank=0 anyway.
  248. // Old BeRoTracker versions set trkvers to 0x214 or 0x217.
  249. // <= MPT 1.07 <= MPT 1.16 OpenMPT 1.17-? <= OpenMPT 1.26 definitely not MPT
  250. if((trkvers == 0x0202 || trkvers == 0x0211 || trkvers == 0x0220 || trkvers == 0x0214) && mpr != 0xFF)
  251. {
  252. if(mpr <= 128)
  253. {
  254. mptIns.nMidiProgram = mpr;
  255. }
  256. uint16 bank = mbank[0] | (mbank[1] << 8);
  257. // These versions also ignored the high bank nibble (was only handled correctly in OpenMPT instrument extensions)
  258. if(bank <= 128)
  259. {
  260. mptIns.wMidiBank = bank;
  261. }
  262. } else
  263. {
  264. if(mpr < 128)
  265. {
  266. mptIns.nMidiProgram = mpr + 1;
  267. }
  268. uint16 bank = 0;
  269. if(mbank[0] < 128)
  270. bank = mbank[0] + 1;
  271. if(mbank[1] < 128)
  272. bank += (mbank[1] << 7);
  273. mptIns.wMidiBank = bank;
  274. }
  275. mptIns.nMidiChannel = mch;
  276. if(mptIns.nMidiChannel >= 128)
  277. {
  278. // Handle old format where MIDI channel and Plugin index are stored in the same variable
  279. mptIns.nMixPlug = mptIns.nMidiChannel - 128;
  280. mptIns.nMidiChannel = 0;
  281. }
  282. // Envelope point count. Limited to 25 in IT format.
  283. const uint8 maxNodes = (modFormat & MOD_TYPE_MPT) ? MAX_ENVPOINTS : 25;
  284. // Volume Envelope
  285. volenv.ConvertToMPT(mptIns.VolEnv, 0, maxNodes);
  286. // Panning Envelope
  287. panenv.ConvertToMPT(mptIns.PanEnv, 32, maxNodes);
  288. // Pitch Envelope
  289. pitchenv.ConvertToMPT(mptIns.PitchEnv, 32, maxNodes);
  290. mptIns.PitchEnv.dwFlags.set(ENV_FILTER, (pitchenv.flags & ITEnvelope::envFilter) != 0);
  291. // Sample Map
  292. for(int i = 0; i < 120; i++)
  293. {
  294. uint8 note = keyboard[i * 2];
  295. SAMPLEINDEX ins = keyboard[i * 2 + 1];
  296. if(ins < MAX_SAMPLES)
  297. {
  298. mptIns.Keyboard[i] = ins;
  299. }
  300. if(note < 120)
  301. {
  302. mptIns.NoteMap[i] = note + NOTE_MIN;
  303. } else
  304. {
  305. mptIns.NoteMap[i] = static_cast<uint8>(i + NOTE_MIN);
  306. }
  307. }
  308. return sizeof(ITInstrument);
  309. }
  310. // Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written to file.
  311. uint32 ITInstrumentEx::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile)
  312. {
  313. uint32 instSize = iti.ConvertToIT(mptIns, compatExport, sndFile);
  314. if(compatExport)
  315. {
  316. return instSize;
  317. }
  318. // Sample Map
  319. bool usedExtension = false;
  320. iti.nos = 0;
  321. std::vector<bool> smpCount(sndFile.GetNumSamples(), false);
  322. for(int i = 0; i < 120; i++)
  323. {
  324. const SAMPLEINDEX smp = mptIns.Keyboard[i];
  325. keyboardhi[i] = 0;
  326. if(smp < MAX_SAMPLES)
  327. {
  328. if(smp >= 256)
  329. {
  330. // We need to save the upper byte for this sample index.
  331. iti.keyboard[i * 2 + 1] = static_cast<uint8>(smp & 0xFF);
  332. keyboardhi[i] = static_cast<uint8>(smp >> 8);
  333. usedExtension = true;
  334. }
  335. if(smp && smp <= sndFile.GetNumSamples() && !smpCount[smp - 1])
  336. {
  337. // We haven't considered this sample yet. Update number of samples.
  338. smpCount[smp - 1] = true;
  339. iti.nos++;
  340. }
  341. }
  342. }
  343. if(usedExtension)
  344. {
  345. // If we actually had to extend the sample map, update the magic bytes and instrument size.
  346. memcpy(iti.dummy, "XTPM", 4);
  347. instSize = sizeof(ITInstrumentEx);
  348. }
  349. return instSize;
  350. }
  351. // Convert an ITInstrumentEx to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read.
  352. uint32 ITInstrumentEx::ConvertToMPT(ModInstrument &mptIns, MODTYPE fromType) const
  353. {
  354. uint32 insSize = iti.ConvertToMPT(mptIns, fromType);
  355. // Is this actually an extended instrument?
  356. // Note: OpenMPT 1.20 - 1.22 accidentally wrote "MPTX" here (since revision 1203), while previous versions wrote the reversed version, "XTPM".
  357. if(insSize == 0 || (memcmp(iti.dummy, "MPTX", 4) && memcmp(iti.dummy, "XTPM", 4)))
  358. {
  359. return insSize;
  360. }
  361. // Olivier's MPT Instrument Extension
  362. for(int i = 0; i < 120; i++)
  363. {
  364. mptIns.Keyboard[i] |= ((SAMPLEINDEX)keyboardhi[i] << 8);
  365. }
  366. return sizeof(ITInstrumentEx);
  367. }
  368. // Convert OpenMPT's internal sample representation to an ITSample.
  369. void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType, bool compress, bool compressIT215, bool allowExternal)
  370. {
  371. MemsetZero(*this);
  372. // Header
  373. memcpy(id, "IMPS", 4);
  374. mpt::String::WriteBuf(mpt::String::nullTerminated, filename) = mptSmp.filename;
  375. //mpt::String::WriteBuf(mpt::String::nullTerminated, name) = m_szNames[nsmp];
  376. // Volume / Panning
  377. gvl = static_cast<uint8>(mptSmp.nGlobalVol);
  378. vol = static_cast<uint8>(mptSmp.nVolume / 4);
  379. dfp = static_cast<uint8>(mptSmp.nPan / 4);
  380. if(mptSmp.uFlags[CHN_PANNING]) dfp |= ITSample::enablePanning;
  381. // Sample Format / Loop Flags
  382. if(mptSmp.HasSampleData() && !mptSmp.uFlags[CHN_ADLIB])
  383. {
  384. flags = ITSample::sampleDataPresent;
  385. if(mptSmp.uFlags[CHN_LOOP]) flags |= ITSample::sampleLoop;
  386. if(mptSmp.uFlags[CHN_SUSTAINLOOP]) flags |= ITSample::sampleSustain;
  387. if(mptSmp.uFlags[CHN_PINGPONGLOOP]) flags |= ITSample::sampleBidiLoop;
  388. if(mptSmp.uFlags[CHN_PINGPONGSUSTAIN]) flags |= ITSample::sampleBidiSustain;
  389. if(mptSmp.uFlags[CHN_STEREO])
  390. {
  391. flags |= ITSample::sampleStereo;
  392. }
  393. if(mptSmp.uFlags[CHN_16BIT])
  394. {
  395. flags |= ITSample::sample16Bit;
  396. }
  397. cvt = ITSample::cvtSignedSample;
  398. if(compress)
  399. {
  400. flags |= ITSample::sampleCompressed;
  401. if(compressIT215)
  402. {
  403. cvt |= ITSample::cvtDelta;
  404. }
  405. }
  406. } else
  407. {
  408. flags = 0x00;
  409. }
  410. // Frequency
  411. C5Speed = mptSmp.nC5Speed ? mptSmp.nC5Speed : 8363;
  412. // Size and loops
  413. length = mpt::saturate_cast<uint32>(mptSmp.nLength);
  414. loopbegin = mpt::saturate_cast<uint32>(mptSmp.nLoopStart);
  415. loopend = mpt::saturate_cast<uint32>(mptSmp.nLoopEnd);
  416. susloopbegin = mpt::saturate_cast<uint32>(mptSmp.nSustainStart);
  417. susloopend = mpt::saturate_cast<uint32>(mptSmp.nSustainEnd);
  418. // Auto Vibrato settings
  419. vit = AutoVibratoXM2IT[mptSmp.nVibType & 7];
  420. vis = std::min(mptSmp.nVibRate, uint8(64));
  421. vid = std::min(mptSmp.nVibDepth, uint8(32));
  422. vir = std::min(mptSmp.nVibSweep, uint8(255));
  423. if((vid | vis) != 0 && (fromType & MOD_TYPE_XM))
  424. {
  425. // Sweep is upside down in XM
  426. if(mptSmp.nVibSweep != 0)
  427. vir = mpt::saturate_cast<decltype(vir)::base_type>(Util::muldivr_unsigned(mptSmp.nVibDepth, 256, mptSmp.nVibSweep));
  428. else
  429. vir = 255;
  430. }
  431. if(mptSmp.uFlags[CHN_ADLIB])
  432. {
  433. length = 12;
  434. flags = ITSample::sampleDataPresent;
  435. cvt = ITSample::cvtOPLInstrument;
  436. } else if(mptSmp.uFlags[SMP_KEEPONDISK])
  437. {
  438. #ifndef MPT_EXTERNAL_SAMPLES
  439. allowExternal = false;
  440. #endif // MPT_EXTERNAL_SAMPLES
  441. // Save external sample (filename at sample pointer)
  442. if(allowExternal && mptSmp.HasSampleData())
  443. {
  444. cvt = ITSample::cvtExternalSample;
  445. } else
  446. {
  447. length = loopbegin = loopend = susloopbegin = susloopend = 0;
  448. }
  449. }
  450. }
  451. // Convert an ITSample to OpenMPT's internal sample representation.
  452. uint32 ITSample::ConvertToMPT(ModSample &mptSmp) const
  453. {
  454. if(memcmp(id, "IMPS", 4))
  455. {
  456. return 0;
  457. }
  458. mptSmp.Initialize(MOD_TYPE_IT);
  459. mptSmp.SetDefaultCuePoints(); // For old IT/MPTM files
  460. mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename);
  461. // Volume / Panning
  462. mptSmp.nVolume = vol * 4;
  463. LimitMax(mptSmp.nVolume, uint16(256));
  464. mptSmp.nGlobalVol = gvl;
  465. LimitMax(mptSmp.nGlobalVol, uint16(64));
  466. mptSmp.nPan = (dfp & 0x7F) * 4;
  467. LimitMax(mptSmp.nPan, uint16(256));
  468. if(dfp & ITSample::enablePanning) mptSmp.uFlags.set(CHN_PANNING);
  469. // Loop Flags
  470. if(flags & ITSample::sampleLoop) mptSmp.uFlags.set(CHN_LOOP);
  471. if(flags & ITSample::sampleSustain) mptSmp.uFlags.set(CHN_SUSTAINLOOP);
  472. if(flags & ITSample::sampleBidiLoop) mptSmp.uFlags.set(CHN_PINGPONGLOOP);
  473. if(flags & ITSample::sampleBidiSustain) mptSmp.uFlags.set(CHN_PINGPONGSUSTAIN);
  474. // Frequency
  475. mptSmp.nC5Speed = C5Speed;
  476. if(!mptSmp.nC5Speed) mptSmp.nC5Speed = 8363;
  477. if(mptSmp.nC5Speed < 256) mptSmp.nC5Speed = 256;
  478. // Size and loops
  479. mptSmp.nLength = length;
  480. mptSmp.nLoopStart = loopbegin;
  481. mptSmp.nLoopEnd = loopend;
  482. mptSmp.nSustainStart = susloopbegin;
  483. mptSmp.nSustainEnd = susloopend;
  484. mptSmp.SanitizeLoops();
  485. // Auto Vibrato settings
  486. mptSmp.nVibType = static_cast<VibratoType>(AutoVibratoIT2XM[vit & 7]);
  487. mptSmp.nVibRate = vis;
  488. mptSmp.nVibDepth = vid & 0x7F;
  489. mptSmp.nVibSweep = vir;
  490. if(cvt == ITSample::cvtOPLInstrument)
  491. {
  492. // FM instrument in MPTM
  493. mptSmp.uFlags.set(CHN_ADLIB);
  494. } else if(cvt == ITSample::cvtExternalSample)
  495. {
  496. // Read external sample (filename at sample pointer)
  497. mptSmp.uFlags.set(SMP_KEEPONDISK);
  498. }
  499. return samplepointer;
  500. }
  501. // Retrieve the internal sample format flags for this instrument.
  502. SampleIO ITSample::GetSampleFormat(uint16 cwtv) const
  503. {
  504. SampleIO sampleIO(
  505. (flags & ITSample::sample16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
  506. SampleIO::mono,
  507. SampleIO::littleEndian,
  508. (cvt & ITSample::cvtSignedSample) ? SampleIO::signedPCM: SampleIO::unsignedPCM);
  509. // Some old version of IT didn't clear the stereo flag when importing samples. Luckily, all other trackers are identifying as IT 2.14+, so let's check for old IT versions.
  510. if((flags & ITSample::sampleStereo) && cwtv >= 0x214)
  511. {
  512. sampleIO |= SampleIO::stereoSplit;
  513. }
  514. if(flags & ITSample::sampleCompressed)
  515. {
  516. // IT 2.14 packed sample
  517. sampleIO |= (cvt & ITSample::cvtDelta) ? SampleIO::IT215 : SampleIO::IT214;
  518. } else
  519. {
  520. // MODPlugin :(
  521. if(!(flags & ITSample::sample16Bit) && cvt == ITSample::cvtADPCMSample)
  522. {
  523. sampleIO |= SampleIO::ADPCM;
  524. } else
  525. {
  526. // ITTECH.TXT says these convert flags are "safe to ignore". IT doesn't ignore them, though, so why should we? :)
  527. if(cvt & ITSample::cvtBigEndian)
  528. {
  529. sampleIO |= SampleIO::bigEndian;
  530. }
  531. if(cvt & ITSample::cvtDelta)
  532. {
  533. sampleIO |= SampleIO::deltaPCM;
  534. }
  535. if((cvt & ITSample::cvtPTM8to16) && (flags & ITSample::sample16Bit))
  536. {
  537. sampleIO |= SampleIO::PTM8Dto16;
  538. }
  539. }
  540. }
  541. return sampleIO;
  542. }
  543. // Convert an ITHistoryStruct to OpenMPT's internal edit history representation
  544. void ITHistoryStruct::ConvertToMPT(FileHistory &mptHistory) const
  545. {
  546. // Decode FAT date and time
  547. MemsetZero(mptHistory.loadDate);
  548. if(fatdate != 0 || fattime != 0)
  549. {
  550. mptHistory.loadDate.tm_year = ((fatdate >> 9) & 0x7F) + 80;
  551. mptHistory.loadDate.tm_mon = Clamp((fatdate >> 5) & 0x0F, 1, 12) - 1;
  552. mptHistory.loadDate.tm_mday = Clamp(fatdate & 0x1F, 1, 31);
  553. mptHistory.loadDate.tm_hour = Clamp((fattime >> 11) & 0x1F, 0, 23);
  554. mptHistory.loadDate.tm_min = Clamp((fattime >> 5) & 0x3F, 0, 59);
  555. mptHistory.loadDate.tm_sec = Clamp((fattime & 0x1F) * 2, 0, 59);
  556. }
  557. mptHistory.openTime = static_cast<uint32>(runtime * (HISTORY_TIMER_PRECISION / 18.2));
  558. }
  559. // Convert OpenMPT's internal edit history representation to an ITHistoryStruct
  560. void ITHistoryStruct::ConvertToIT(const FileHistory &mptHistory)
  561. {
  562. // Create FAT file dates
  563. if(mptHistory.HasValidDate())
  564. {
  565. fatdate = static_cast<uint16>(mptHistory.loadDate.tm_mday | ((mptHistory.loadDate.tm_mon + 1) << 5) | ((mptHistory.loadDate.tm_year - 80) << 9));
  566. fattime = static_cast<uint16>((mptHistory.loadDate.tm_sec / 2) | (mptHistory.loadDate.tm_min << 5) | (mptHistory.loadDate.tm_hour << 11));
  567. } else
  568. {
  569. fatdate = 0;
  570. fattime = 0;
  571. }
  572. runtime = static_cast<uint32>(mptHistory.openTime * (18.2 / HISTORY_TIMER_PRECISION));
  573. }
  574. uint32 DecodeITEditTimer(uint16 cwtv, uint32 editTime)
  575. {
  576. if((cwtv & 0xFFF) >= 0x0208)
  577. {
  578. editTime ^= 0x4954524B; // 'ITRK'
  579. editTime = mpt::rotr(editTime, 7);
  580. editTime = ~editTime + 1;
  581. editTime = mpt::rotl(editTime, 4);
  582. editTime ^= 0x4A54484C; // 'JTHL'
  583. }
  584. return editTime;
  585. }
  586. OPENMPT_NAMESPACE_END