1
0

Load_mt2.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. /*
  2. * Load_mt2.cpp
  3. * ------------
  4. * Purpose: MT2 (MadTracker 2) module loader
  5. * Notes : A couple of things are not handled properly or not at all, such as internal effects and automation envelopes
  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. #ifdef MPT_EXTERNAL_SAMPLES
  13. // For loading external samples
  14. #include "../common/mptPathString.h"
  15. #endif // MPT_EXTERNAL_SAMPLES
  16. #ifdef MPT_WITH_VST
  17. #include "../mptrack/Vstplug.h"
  18. #endif // MPT_WITH_VST
  19. OPENMPT_NAMESPACE_BEGIN
  20. struct MT2FileHeader
  21. {
  22. enum MT2HeaderFlags
  23. {
  24. packedPatterns = 0x01,
  25. automation = 0x02,
  26. drumsAutomation = 0x08,
  27. masterAutomation = 0x10,
  28. };
  29. char signature[4]; // "MT20"
  30. uint32le userID;
  31. uint16le version;
  32. char trackerName[32]; // "MadTracker 2.0"
  33. char songName[64];
  34. uint16le numOrders;
  35. uint16le restartPos;
  36. uint16le numPatterns;
  37. uint16le numChannels;
  38. uint16le samplesPerTick;
  39. uint8le ticksPerLine;
  40. uint8le linesPerBeat;
  41. uint32le flags; // See HeaderFlags
  42. uint16le numInstruments;
  43. uint16le numSamples;
  44. };
  45. MPT_BINARY_STRUCT(MT2FileHeader, 126)
  46. struct MT2DrumsData
  47. {
  48. uint16le numDrumPatterns;
  49. uint16le DrumSamples[8];
  50. uint8le DrumPatternOrder[256];
  51. };
  52. MPT_BINARY_STRUCT(MT2DrumsData, 274)
  53. struct MT2TrackSettings
  54. {
  55. uint16le volume;
  56. uint8le trackfx; // Built-in effect type is used
  57. uint8le output;
  58. uint16le fxID;
  59. uint16le trackEffectParam[64][8];
  60. };
  61. MPT_BINARY_STRUCT(MT2TrackSettings, 1030)
  62. struct MT2Command
  63. {
  64. uint8 note; // 0=nothing, 97=note off
  65. uint8 instr;
  66. uint8 vol;
  67. uint8 pan;
  68. uint8 fxcmd;
  69. uint8 fxparam1;
  70. uint8 fxparam2;
  71. };
  72. MPT_BINARY_STRUCT(MT2Command, 7)
  73. struct MT2EnvPoint
  74. {
  75. uint16le x;
  76. uint16le y;
  77. };
  78. MPT_BINARY_STRUCT(MT2EnvPoint, 4)
  79. struct MT2Instrument
  80. {
  81. enum EnvTypes
  82. {
  83. VolumeEnv = 1,
  84. PanningEnv = 2,
  85. PitchEnv = 4,
  86. FilterEnv = 8,
  87. };
  88. uint16le numSamples;
  89. uint8le groupMap[96];
  90. uint8le vibtype, vibsweep, vibdepth, vibrate;
  91. uint16le fadeout;
  92. uint16le nna;
  93. };
  94. MPT_BINARY_STRUCT(MT2Instrument, 106)
  95. struct MT2IEnvelope
  96. {
  97. uint8le flags;
  98. uint8le numPoints;
  99. uint8le sustainPos;
  100. uint8le loopStart;
  101. uint8le loopEnd;
  102. uint8le reserved[3];
  103. MT2EnvPoint points[16];
  104. };
  105. MPT_BINARY_STRUCT(MT2IEnvelope, 72)
  106. // Note: The order of these fields differs a bit in MTIOModule_MT2.cpp - maybe just typos, I'm not sure.
  107. // This struct follows the save format of MadTracker 2.6.1.
  108. struct MT2InstrSynth
  109. {
  110. uint8le synthID;
  111. uint8le effectID; // 0 = Lowpass filter, 1 = Highpass filter
  112. uint16le cutoff; // 100...11000 Hz
  113. uint8le resonance; // 0...128
  114. uint8le attack; // 0...128
  115. uint8le decay; // 0...128
  116. uint8le midiChannel; // 0...15
  117. int8le device; // VST slot (positive) or MIDI device (negative)
  118. int8le unknown1; // Missing in MTIOModule_MT2.cpp
  119. uint8le volume; // 0...255
  120. int8le finetune; // -96...96
  121. int8le transpose; // -48...48
  122. uint8le unknown2; // Seems to be equal to instrument number.
  123. uint8le unknown3;
  124. uint8le midiProgram;
  125. uint8le reserved[16];
  126. };
  127. MPT_BINARY_STRUCT(MT2InstrSynth, 32)
  128. struct MT2Sample
  129. {
  130. uint32le length;
  131. uint32le frequency;
  132. uint8le depth;
  133. uint8le channels;
  134. uint8le flags;
  135. uint8le loopType;
  136. uint32le loopStart;
  137. uint32le loopEnd;
  138. uint16le volume;
  139. int8le panning;
  140. int8le note;
  141. int16le spb;
  142. };
  143. MPT_BINARY_STRUCT(MT2Sample, 26)
  144. struct MT2Group
  145. {
  146. uint8le sample;
  147. uint8le vol; // 0...128
  148. int8le pitch; // -128...127
  149. uint8le reserved[5];
  150. };
  151. MPT_BINARY_STRUCT(MT2Group, 8)
  152. struct MT2VST
  153. {
  154. char dll[64];
  155. char programName[28];
  156. uint32le fxID;
  157. uint32le fxVersion;
  158. uint32le programNr;
  159. uint8le useChunks;
  160. uint8le track;
  161. int8le pan; // Not imported - could use pan mix mode for D/W ratio, but this is not implemented for instrument plugins!
  162. char reserved[17];
  163. uint32le n;
  164. };
  165. MPT_BINARY_STRUCT(MT2VST, 128)
  166. static bool ConvertMT2Command(CSoundFile *that, ModCommand &m, MT2Command &p)
  167. {
  168. bool hasLegacyTempo = false;
  169. // Note
  170. m.note = NOTE_NONE;
  171. if(p.note) m.note = (p.note > 96) ? NOTE_KEYOFF : (p.note + NOTE_MIN + 11);
  172. // Instrument
  173. m.instr = p.instr;
  174. // Volume Column
  175. if(p.vol >= 0x10 && p.vol <= 0x90)
  176. {
  177. m.volcmd = VOLCMD_VOLUME;
  178. m.vol = (p.vol - 0x10) / 2;
  179. } else if(p.vol >= 0xA0 && p.vol <= 0xAF)
  180. {
  181. m.volcmd = VOLCMD_VOLSLIDEDOWN;
  182. m.vol = (p.vol & 0x0F);
  183. } else if(p.vol >= 0xB0 && p.vol <= 0xBF)
  184. {
  185. m.volcmd = VOLCMD_VOLSLIDEUP;
  186. m.vol = (p.vol & 0x0F);
  187. } else if(p.vol >= 0xC0 && p.vol <= 0xCF)
  188. {
  189. m.volcmd = VOLCMD_FINEVOLDOWN;
  190. m.vol = (p.vol & 0x0F);
  191. } else if(p.vol >= 0xD0 && p.vol <= 0xDF)
  192. {
  193. m.volcmd = VOLCMD_FINEVOLUP;
  194. m.vol = (p.vol & 0x0F);
  195. }
  196. // Effects
  197. if(p.fxcmd || p.fxparam1 || p.fxparam2)
  198. {
  199. switch(p.fxcmd)
  200. {
  201. case 0x00: // FastTracker effect
  202. m.command = p.fxparam2;
  203. m.param = p.fxparam1;
  204. CSoundFile::ConvertModCommand(m);
  205. #ifdef MODPLUG_TRACKER
  206. m.Convert(MOD_TYPE_XM, MOD_TYPE_IT, *that);
  207. #else
  208. MPT_UNREFERENCED_PARAMETER(that);
  209. #endif // MODPLUG_TRACKER
  210. if(p.fxparam2 == 0x0F)
  211. hasLegacyTempo = true;
  212. break;
  213. case 0x01: // Portamento up (on every tick)
  214. m.command = CMD_PORTAMENTOUP;
  215. m.param = mpt::saturate_cast<ModCommand::PARAM>((p.fxparam2 << 4) | (p.fxparam1 >> 4));
  216. break;
  217. case 0x02: // Portamento down (on every tick)
  218. m.command = CMD_PORTAMENTODOWN;
  219. m.param = mpt::saturate_cast<ModCommand::PARAM>((p.fxparam2 << 4) | (p.fxparam1 >> 4));
  220. break;
  221. case 0x03: // Tone Portamento (on every tick)
  222. m.command = CMD_TONEPORTAMENTO;
  223. m.param = mpt::saturate_cast<ModCommand::PARAM>((p.fxparam2 << 4) | (p.fxparam1 >> 4));
  224. break;
  225. case 0x04: // Vibrato
  226. m.command = CMD_VIBRATO;
  227. m.param = (p.fxparam2 & 0xF0) | (p.fxparam1 >> 4);
  228. break;
  229. case 0x08: // Panning + Polarity (we can only import panning for now)
  230. if(p.fxparam1)
  231. {
  232. m.command = CMD_PANNING8;
  233. m.param = p.fxparam1;
  234. } else if(p.fxparam2 == 1 || p.fxparam2 == 2)
  235. {
  236. // Invert left or right channel
  237. m.command = CMD_S3MCMDEX;
  238. m.param = 0x91;
  239. }
  240. break;
  241. case 0x0C: // Set volume (0x80 = 100%)
  242. m.command = CMD_VOLUME;
  243. m.param = p.fxparam2 / 2;
  244. break;
  245. case 0x0F: // Set tempo, LPB and ticks (we can only import tempo for now)
  246. if(p.fxparam2 != 0)
  247. {
  248. m.command = CMD_TEMPO;
  249. m.param = p.fxparam2;
  250. } else
  251. {
  252. m.command = CMD_SPEED;
  253. m.param = (p.fxparam1 & 0x0F);
  254. }
  255. break;
  256. case 0x10: // Impulse Tracker effect
  257. m.command = p.fxparam2;
  258. m.param = p.fxparam1;
  259. CSoundFile::S3MConvert(m, true);
  260. if(m.command == CMD_TEMPO || m.command == CMD_SPEED)
  261. hasLegacyTempo = true;
  262. break;
  263. case 0x1D: // Gapper (like IT Tremor with old FX, i.e. 1D 00 XY = ontime X + 1 ticks, offtime Y + 1 ticks)
  264. m.command = CMD_TREMOR;
  265. m.param = p.fxparam1;
  266. break;
  267. case 0x20: // Cutoff + Resonance (we can only import cutoff for now)
  268. m.command = CMD_MIDI;
  269. m.param = p.fxparam2 >> 1;
  270. break;
  271. case 0x22: // Cutoff + Resonance + Attack + Decay (we can only import cutoff for now)
  272. m.command = CMD_MIDI;
  273. m.param = (p.fxparam2 & 0xF0) >> 1;
  274. break;
  275. case 0x24: // Reverse
  276. m.command = CMD_S3MCMDEX;
  277. m.param = 0x9F;
  278. break;
  279. case 0x80: // Track volume
  280. m.command = CMD_CHANNELVOLUME;
  281. m.param = p.fxparam2 / 4u;
  282. break;
  283. case 0x9D: // Offset + delay
  284. m.volcmd = VOLCMD_OFFSET;
  285. m.vol = p.fxparam2 >> 3;
  286. m.command = CMD_S3MCMDEX;
  287. m.param = 0xD0 | std::min(p.fxparam1, uint8(0x0F));
  288. break;
  289. case 0xCC: // MIDI CC
  290. //m.command = CMD_MIDI;
  291. break;
  292. // TODO: More MT2 Effects
  293. }
  294. }
  295. if(p.pan)
  296. {
  297. if(m.command == CMD_NONE)
  298. {
  299. m.command = CMD_PANNING8;
  300. m.param = p.pan;
  301. } else if(m.volcmd == VOLCMD_NONE)
  302. {
  303. m.volcmd = VOLCMD_PANNING;
  304. m.vol = p.pan / 4;
  305. }
  306. }
  307. return hasLegacyTempo;
  308. }
  309. // This doesn't really do anything but skipping the envelope chunk at the moment.
  310. static void ReadMT2Automation(uint16 version, FileReader &file)
  311. {
  312. uint32 flags;
  313. uint32 trkfxid;
  314. if(version >= 0x203)
  315. {
  316. flags = file.ReadUint32LE();
  317. trkfxid = file.ReadUint32LE();
  318. } else
  319. {
  320. flags = file.ReadUint16LE();
  321. trkfxid = file.ReadUint16LE();
  322. }
  323. MPT_UNREFERENCED_PARAMETER(trkfxid);
  324. while(flags != 0)
  325. {
  326. if(flags & 1)
  327. {
  328. file.Skip(4 + sizeof(MT2EnvPoint) * 64);
  329. }
  330. flags >>= 1;
  331. }
  332. }
  333. static bool ValidateHeader(const MT2FileHeader &fileHeader)
  334. {
  335. if(std::memcmp(fileHeader.signature, "MT20", 4)
  336. || fileHeader.version < 0x200 || fileHeader.version >= 0x300
  337. || fileHeader.numChannels < 1 || fileHeader.numChannels > 64
  338. || fileHeader.numOrders > 256
  339. || fileHeader.numInstruments >= MAX_INSTRUMENTS
  340. || fileHeader.numSamples >= MAX_SAMPLES
  341. )
  342. {
  343. return false;
  344. }
  345. return true;
  346. }
  347. static uint64 GetHeaderMinimumAdditionalSize(const MT2FileHeader &fileHeader)
  348. {
  349. MPT_UNREFERENCED_PARAMETER(fileHeader);
  350. return 256;
  351. }
  352. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize)
  353. {
  354. MT2FileHeader fileHeader;
  355. if(!file.ReadStruct(fileHeader))
  356. {
  357. return ProbeWantMoreData;
  358. }
  359. if(!ValidateHeader(fileHeader))
  360. {
  361. return ProbeFailure;
  362. }
  363. return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
  364. }
  365. bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
  366. {
  367. file.Rewind();
  368. MT2FileHeader fileHeader;
  369. if(!file.ReadStruct(fileHeader))
  370. {
  371. return false;
  372. }
  373. if(!ValidateHeader(fileHeader))
  374. {
  375. return false;
  376. }
  377. if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
  378. {
  379. return false;
  380. }
  381. if(loadFlags == onlyVerifyHeader)
  382. {
  383. return true;
  384. }
  385. InitializeGlobals(MOD_TYPE_MT2);
  386. InitializeChannels();
  387. m_modFormat.formatName = MPT_UFORMAT("MadTracker {}.{}")(fileHeader.version >> 8, mpt::ufmt::hex0<2>(fileHeader.version & 0xFF));
  388. m_modFormat.type = U_("mt2");
  389. m_modFormat.madeWithTracker = mpt::ToUnicode(mpt::Charset::Windows1252, mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.trackerName));
  390. m_modFormat.charset = mpt::Charset::Windows1252;
  391. m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songName);
  392. m_nChannels = fileHeader.numChannels;
  393. m_nDefaultSpeed = Clamp<uint8, uint8>(fileHeader.ticksPerLine, 1, 31);
  394. m_nDefaultTempo.Set(125);
  395. m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX | SONG_EXFILTERRANGE;
  396. m_nInstruments = fileHeader.numInstruments;
  397. m_nSamples = fileHeader.numSamples;
  398. m_nDefaultRowsPerBeat = Clamp<uint8, uint8>(fileHeader.linesPerBeat, 1, 32);
  399. m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat * 4;
  400. m_nVSTiVolume = 48;
  401. m_nSamplePreAmp = 48 * 2; // Double pre-amp because we will halve the volume of all non-drum instruments, because the volume of drum samples can exceed that of normal samples
  402. uint8 orders[256];
  403. file.ReadArray(orders);
  404. ReadOrderFromArray(Order(), orders, fileHeader.numOrders);
  405. Order().SetRestartPos(fileHeader.restartPos);
  406. // This value is supposed to be the size of the drums data, but in old MT2.0 files it's 8 bytes too small.
  407. // MadTracker itself unconditionally reads 274 bytes here if the value is != 0, so we do the same.
  408. const bool hasDrumChannels = file.ReadUint16LE() != 0;
  409. FileReader drumData = file.ReadChunk(hasDrumChannels ? sizeof(MT2DrumsData) : 0);
  410. FileReader extraData = file.ReadChunk(file.ReadUint32LE());
  411. const CHANNELINDEX channelsWithoutDrums = m_nChannels;
  412. static_assert(MAX_BASECHANNELS >= 64 + 8);
  413. if(hasDrumChannels)
  414. {
  415. m_nChannels += 8;
  416. }
  417. bool hasLegacyTempo = false;
  418. // Read patterns
  419. if(loadFlags & loadPatternData)
  420. Patterns.ResizeArray(fileHeader.numPatterns);
  421. for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
  422. {
  423. ROWINDEX numRows = file.ReadUint16LE();
  424. FileReader chunk = file.ReadChunk((file.ReadUint32LE() + 1) & ~1);
  425. LimitMax(numRows, MAX_PATTERN_ROWS);
  426. if(!numRows
  427. || !(loadFlags & loadPatternData)
  428. || !Patterns.Insert(pat, numRows))
  429. {
  430. continue;
  431. }
  432. if(fileHeader.flags & MT2FileHeader::packedPatterns)
  433. {
  434. ROWINDEX row = 0;
  435. CHANNELINDEX chn = 0;
  436. while(chunk.CanRead(1))
  437. {
  438. MT2Command cmd;
  439. uint8 infobyte = chunk.ReadUint8();
  440. uint8 repeatCount = 0;
  441. if(infobyte == 0xFF)
  442. {
  443. repeatCount = chunk.ReadUint8();
  444. infobyte = chunk.ReadUint8();
  445. }
  446. if(infobyte & 0x7F)
  447. {
  448. ModCommand *m = Patterns[pat].GetpModCommand(row, chn);
  449. MemsetZero(cmd);
  450. if(infobyte & 0x01) cmd.note = chunk.ReadUint8();
  451. if(infobyte & 0x02) cmd.instr = chunk.ReadUint8();
  452. if(infobyte & 0x04) cmd.vol = chunk.ReadUint8();
  453. if(infobyte & 0x08) cmd.pan = chunk.ReadUint8();
  454. if(infobyte & 0x10) cmd.fxcmd = chunk.ReadUint8();
  455. if(infobyte & 0x20) cmd.fxparam1 = chunk.ReadUint8();
  456. if(infobyte & 0x40) cmd.fxparam2 = chunk.ReadUint8();
  457. hasLegacyTempo |= ConvertMT2Command(this, *m, cmd);
  458. const ModCommand &orig = *m;
  459. const ROWINDEX fillRows = std::min((uint32)repeatCount, (uint32)numRows - (row + 1));
  460. for(ROWINDEX r = 0; r < fillRows; r++)
  461. {
  462. m += GetNumChannels();
  463. // cppcheck false-positive
  464. // cppcheck-suppress selfAssignment
  465. *m = orig;
  466. }
  467. }
  468. row += repeatCount + 1;
  469. while(row >= numRows) { row -= numRows; chn++; }
  470. if(chn >= channelsWithoutDrums) break;
  471. }
  472. } else
  473. {
  474. for(ROWINDEX row = 0; row < numRows; row++)
  475. {
  476. auto rowData = Patterns[pat].GetRow(row);
  477. for(CHANNELINDEX chn = 0; chn < channelsWithoutDrums; chn++)
  478. {
  479. MT2Command cmd;
  480. chunk.ReadStruct(cmd);
  481. hasLegacyTempo |= ConvertMT2Command(this, rowData[chn], cmd);
  482. }
  483. }
  484. }
  485. }
  486. if(fileHeader.samplesPerTick > 1 && fileHeader.samplesPerTick < 5000)
  487. {
  488. if(hasLegacyTempo)
  489. {
  490. m_nDefaultTempo.SetRaw(Util::muldivr(110250, TEMPO::fractFact, fileHeader.samplesPerTick));
  491. m_nTempoMode = TempoMode::Classic;
  492. } else
  493. {
  494. m_nDefaultTempo = TEMPO(44100.0 * 60.0 / (m_nDefaultSpeed * m_nDefaultRowsPerBeat * fileHeader.samplesPerTick));
  495. m_nTempoMode = TempoMode::Modern;
  496. }
  497. }
  498. // Read extra data
  499. uint32 numVST = 0;
  500. std::vector<int8> trackRouting(GetNumChannels(), 0);
  501. while(extraData.CanRead(8))
  502. {
  503. uint32 id = extraData.ReadUint32LE();
  504. FileReader chunk = extraData.ReadChunk(extraData.ReadUint32LE());
  505. switch(id)
  506. {
  507. case MagicLE("BPM+"):
  508. if(!hasLegacyTempo)
  509. {
  510. m_nTempoMode = TempoMode::Modern;
  511. double d = chunk.ReadDoubleLE();
  512. if(d > 0.00000001)
  513. {
  514. m_nDefaultTempo = TEMPO(44100.0 * 60.0 / (m_nDefaultSpeed * m_nDefaultRowsPerBeat * d));
  515. }
  516. }
  517. break;
  518. case MagicLE("TFXM"):
  519. break;
  520. case MagicLE("TRKO"):
  521. break;
  522. case MagicLE("TRKS"):
  523. m_nSamplePreAmp = chunk.ReadUint16LE() / 256u; // 131072 is 0dB... I think (that's how MTIOModule_MT2.cpp reads)
  524. // Dirty workaround for modules that use track automation for a fade-in at the song start (e.g. Rock.mt2)
  525. if(!m_nSamplePreAmp)
  526. m_nSamplePreAmp = 48;
  527. m_nVSTiVolume = m_nSamplePreAmp / 2u;
  528. for(CHANNELINDEX c = 0; c < GetNumChannels(); c++)
  529. {
  530. MT2TrackSettings trackSettings;
  531. if(chunk.ReadStruct(trackSettings))
  532. {
  533. ChnSettings[c].nVolume = static_cast<uint8>(trackSettings.volume >> 10); // 32768 is 0dB
  534. trackRouting[c] = trackSettings.output;
  535. }
  536. }
  537. break;
  538. case MagicLE("TRKL"):
  539. for(CHANNELINDEX i = 0; i < m_nChannels && chunk.CanRead(1); i++)
  540. {
  541. std::string name;
  542. chunk.ReadNullString(name);
  543. ChnSettings[i].szName = mpt::String::ReadBuf(mpt::String::spacePadded, name.c_str(), name.length());
  544. }
  545. break;
  546. case MagicLE("PATN"):
  547. for(PATTERNINDEX i = 0; i < fileHeader.numPatterns && chunk.CanRead(1) && Patterns.IsValidIndex(i); i++)
  548. {
  549. std::string name;
  550. chunk.ReadNullString(name);
  551. Patterns[i].SetName(name);
  552. }
  553. break;
  554. case MagicLE("MSG\0"):
  555. chunk.Skip(1); // Show message on startup
  556. m_songMessage.Read(chunk, chunk.BytesLeft(), SongMessage::leCRLF);
  557. break;
  558. case MagicLE("PICT"):
  559. break;
  560. case MagicLE("SUM\0"):
  561. {
  562. uint8 summaryMask[6];
  563. chunk.ReadArray(summaryMask);
  564. std::string artist;
  565. chunk.ReadNullString(artist);
  566. if(artist != "Unregistered")
  567. {
  568. m_songArtist = mpt::ToUnicode(mpt::Charset::Windows1252, artist);
  569. }
  570. }
  571. break;
  572. case MagicLE("TMAP"):
  573. break;
  574. case MagicLE("MIDI"):
  575. break;
  576. case MagicLE("TREQ"):
  577. break;
  578. case MagicLE("VST2"):
  579. numVST = chunk.ReadUint32LE();
  580. #ifdef MPT_WITH_VST
  581. if(!(loadFlags & loadPluginData))
  582. {
  583. break;
  584. }
  585. for(uint32 i = 0; i < std::min(numVST, uint32(MAX_MIXPLUGINS)); i++)
  586. {
  587. MT2VST vstHeader;
  588. if(chunk.ReadStruct(vstHeader))
  589. {
  590. if(fileHeader.version >= 0x0250)
  591. chunk.Skip(16 * 4); // Parameter automation map for 16 parameters
  592. SNDMIXPLUGIN &mixPlug = m_MixPlugins[i];
  593. mixPlug.Destroy();
  594. std::string libraryName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, vstHeader.dll);
  595. mixPlug.Info.szName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, vstHeader.programName);
  596. if(libraryName.length() > 4 && libraryName[libraryName.length() - 4] == '.')
  597. {
  598. // Remove ".dll" from library name
  599. libraryName.resize(libraryName.length() - 4 );
  600. }
  601. mixPlug.Info.szLibraryName = libraryName;
  602. mixPlug.Info.dwPluginId1 = Vst::kEffectMagic;
  603. mixPlug.Info.dwPluginId2 = vstHeader.fxID;
  604. if(vstHeader.track >= m_nChannels)
  605. {
  606. mixPlug.SetMasterEffect(true);
  607. } else
  608. {
  609. if(!ChnSettings[vstHeader.track].nMixPlugin)
  610. {
  611. ChnSettings[vstHeader.track].nMixPlugin = static_cast<PLUGINDEX>(i + 1);
  612. } else
  613. {
  614. // Channel already has plugin assignment - chain the plugins
  615. PLUGINDEX outPlug = ChnSettings[vstHeader.track].nMixPlugin - 1;
  616. while(true)
  617. {
  618. if(m_MixPlugins[outPlug].GetOutputPlugin() == PLUGINDEX_INVALID)
  619. {
  620. m_MixPlugins[outPlug].SetOutputPlugin(static_cast<PLUGINDEX>(i));
  621. break;
  622. }
  623. outPlug = m_MixPlugins[outPlug].GetOutputPlugin();
  624. }
  625. }
  626. }
  627. // Read plugin settings
  628. uint32 dataSize;
  629. if(vstHeader.useChunks)
  630. {
  631. // MT2 only ever calls effGetChunk for programs, and OpenMPT uses the defaultProgram value to determine
  632. // whether it should use effSetChunk for programs or banks...
  633. mixPlug.defaultProgram = -1;
  634. LimitMax(vstHeader.n, std::numeric_limits<decltype(dataSize)>::max() - 4);
  635. dataSize = vstHeader.n + 4;
  636. } else
  637. {
  638. mixPlug.defaultProgram = vstHeader.programNr;
  639. LimitMax(vstHeader.n, (std::numeric_limits<decltype(dataSize)>::max() / 4u) - 1);
  640. dataSize = vstHeader.n * 4 + 4;
  641. }
  642. mixPlug.pluginData.resize(dataSize);
  643. if(vstHeader.useChunks)
  644. {
  645. std::memcpy(mixPlug.pluginData.data(), "fEvN", 4); // 'NvEf' plugin data type
  646. chunk.ReadRaw(mpt::span(mixPlug.pluginData.data() + 4, vstHeader.n));
  647. } else
  648. {
  649. auto memFile = std::make_pair(mpt::as_span(mixPlug.pluginData), mpt::IO::Offset(0));
  650. mpt::IO::WriteIntLE<uint32>(memFile, 0); // Plugin data type
  651. for(uint32 param = 0; param < vstHeader.n; param++)
  652. {
  653. mpt::IO::Write(memFile, IEEE754binary32LE{chunk.ReadFloatLE()});
  654. }
  655. }
  656. } else
  657. {
  658. break;
  659. }
  660. }
  661. #endif // MPT_WITH_VST
  662. break;
  663. }
  664. }
  665. #ifndef NO_PLUGINS
  666. // Now that we have both the track settings and plugins, establish the track routing by applying the same plugins to the source track as to the target track:
  667. for(CHANNELINDEX c = 0; c < GetNumChannels(); c++)
  668. {
  669. int8 outTrack = trackRouting[c];
  670. if(outTrack > c && outTrack < GetNumChannels() && ChnSettings[outTrack].nMixPlugin != 0)
  671. {
  672. if(ChnSettings[c].nMixPlugin == 0)
  673. {
  674. ChnSettings[c].nMixPlugin = ChnSettings[outTrack].nMixPlugin;
  675. } else
  676. {
  677. PLUGINDEX outPlug = ChnSettings[c].nMixPlugin - 1;
  678. for(;;)
  679. {
  680. if(m_MixPlugins[outPlug].GetOutputPlugin() == PLUGINDEX_INVALID)
  681. {
  682. m_MixPlugins[outPlug].SetOutputPlugin(ChnSettings[outTrack].nMixPlugin - 1);
  683. break;
  684. }
  685. outPlug = m_MixPlugins[outPlug].GetOutputPlugin();
  686. }
  687. }
  688. }
  689. }
  690. #endif // NO_PLUGINS
  691. // Read drum channels
  692. INSTRUMENTINDEX drumMap[8] = { 0 };
  693. uint16 drumSample[8] = { 0 };
  694. if(hasDrumChannels)
  695. {
  696. MT2DrumsData drumHeader;
  697. drumData.ReadStruct(drumHeader);
  698. // Allocate some instruments to handle the drum samples
  699. for(INSTRUMENTINDEX i = 0; i < 8; i++)
  700. {
  701. drumMap[i] = GetNextFreeInstrument(m_nInstruments + 1);
  702. drumSample[i] = drumHeader.DrumSamples[i];
  703. if(drumMap[i] != INSTRUMENTINDEX_INVALID)
  704. {
  705. ModInstrument *mptIns = AllocateInstrument(drumMap[i], drumHeader.DrumSamples[i] + 1);
  706. if(mptIns != nullptr)
  707. {
  708. mptIns->name = MPT_AFORMAT("Drum #{}")(i+1);
  709. }
  710. } else
  711. {
  712. drumMap[i] = 0;
  713. }
  714. }
  715. // Get all the drum pattern chunks
  716. std::vector<FileReader> patternChunks(drumHeader.numDrumPatterns);
  717. for(uint32 pat = 0; pat < drumHeader.numDrumPatterns; pat++)
  718. {
  719. uint16 numRows = file.ReadUint16LE();
  720. patternChunks[pat] = file.ReadChunk(numRows * 32);
  721. }
  722. std::vector<PATTERNINDEX> patMapping(fileHeader.numPatterns, PATTERNINDEX_INVALID);
  723. for(uint32 ord = 0; ord < fileHeader.numOrders; ord++)
  724. {
  725. if(drumHeader.DrumPatternOrder[ord] >= drumHeader.numDrumPatterns || Order()[ord] >= fileHeader.numPatterns)
  726. continue;
  727. // Figure out where to write this drum pattern
  728. PATTERNINDEX writePat = Order()[ord];
  729. if(patMapping[writePat] == PATTERNINDEX_INVALID)
  730. {
  731. patMapping[writePat] = drumHeader.DrumPatternOrder[ord];
  732. } else if(patMapping[writePat] != drumHeader.DrumPatternOrder[ord])
  733. {
  734. // Damn, this pattern has previously used a different drum pattern. Duplicate it...
  735. PATTERNINDEX newPat = Patterns.Duplicate(writePat);
  736. if(newPat != PATTERNINDEX_INVALID)
  737. {
  738. writePat = newPat;
  739. Order()[ord] = writePat;
  740. }
  741. }
  742. if(!Patterns.IsValidPat(writePat))
  743. continue;
  744. FileReader &chunk = patternChunks[drumHeader.DrumPatternOrder[ord]];
  745. chunk.Rewind();
  746. const ROWINDEX numRows = static_cast<ROWINDEX>(chunk.GetLength() / 32u);
  747. for(ROWINDEX row = 0; row < Patterns[writePat].GetNumRows(); row++)
  748. {
  749. ModCommand *m = Patterns[writePat].GetpModCommand(row, m_nChannels - 8);
  750. for(CHANNELINDEX chn = 0; chn < 8; chn++, m++)
  751. {
  752. *m = ModCommand::Empty();
  753. if(row >= numRows)
  754. continue;
  755. uint8 drums[4];
  756. chunk.ReadArray(drums);
  757. if(drums[0] & 0x80)
  758. {
  759. m->note = NOTE_MIDDLEC;
  760. m->instr = static_cast<ModCommand::INSTR>(drumMap[chn]);
  761. uint8 delay = drums[0] & 0x1F;
  762. if(delay)
  763. {
  764. LimitMax(delay, uint8(0x0F));
  765. m->command = CMD_S3MCMDEX;
  766. m->param = 0xD0 | delay;
  767. }
  768. m->volcmd = VOLCMD_VOLUME;
  769. // Volume is 0...255, but 128 is equivalent to v64 - we compensate this by halving the global volume of all non-drum instruments
  770. m->vol = static_cast<ModCommand::VOL>((static_cast<uint16>(drums[1]) + 3) / 4u);
  771. }
  772. }
  773. }
  774. }
  775. }
  776. // Read automation envelopes
  777. if(fileHeader.flags & MT2FileHeader::automation)
  778. {
  779. const uint32 numEnvelopes = ((fileHeader.flags & MT2FileHeader::drumsAutomation) ? m_nChannels : channelsWithoutDrums)
  780. + ((fileHeader.version >= 0x0250) ? numVST : 0)
  781. + ((fileHeader.flags & MT2FileHeader::masterAutomation) ? 1 : 0);
  782. for(uint32 pat = 0; pat < fileHeader.numPatterns; pat++)
  783. {
  784. for(uint32 env = 0; env < numEnvelopes && file.CanRead(4); env++)
  785. {
  786. // TODO
  787. ReadMT2Automation(fileHeader.version, file);
  788. }
  789. }
  790. }
  791. // Read instruments
  792. std::vector<FileReader> instrChunks(255);
  793. for(INSTRUMENTINDEX i = 0; i < 255; i++)
  794. {
  795. char instrName[32];
  796. file.ReadArray(instrName);
  797. uint32 dataLength = file.ReadUint32LE();
  798. if(dataLength == 32) dataLength += 108 + sizeof(MT2IEnvelope) * 4;
  799. if(fileHeader.version > 0x0201 && dataLength) dataLength += 4;
  800. FileReader instrChunk = instrChunks[i] = file.ReadChunk(dataLength);
  801. ModInstrument *mptIns = nullptr;
  802. if(i < fileHeader.numInstruments)
  803. {
  804. // Default sample assignment if there is no data chunk? Fixes e.g. instrument 33 in Destiny - Dream Alone.mt2
  805. mptIns = AllocateInstrument(i + 1, i + 1);
  806. }
  807. if(mptIns == nullptr)
  808. continue;
  809. mptIns->name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrName);
  810. if(!dataLength)
  811. continue;
  812. MT2Instrument insHeader;
  813. instrChunk.ReadStruct(insHeader);
  814. uint16 flags = 0;
  815. if(fileHeader.version >= 0x0201) flags = instrChunk.ReadUint16LE();
  816. uint32 envMask = MT2Instrument::VolumeEnv | MT2Instrument::PanningEnv;
  817. if(fileHeader.version >= 0x0202) envMask = instrChunk.ReadUint32LE();
  818. mptIns->nFadeOut = insHeader.fadeout;
  819. const NewNoteAction NNA[4] = { NewNoteAction::NoteCut, NewNoteAction::Continue, NewNoteAction::NoteOff, NewNoteAction::NoteFade };
  820. const DuplicateCheckType DCT[4] = { DuplicateCheckType::None, DuplicateCheckType::Note, DuplicateCheckType::Sample, DuplicateCheckType::Instrument };
  821. const DuplicateNoteAction DNA[4] = { DuplicateNoteAction::NoteCut, DuplicateNoteAction::NoteFade /* actually continue, but IT doesn't have that */, DuplicateNoteAction::NoteOff, DuplicateNoteAction::NoteFade };
  822. mptIns->nNNA = NNA[insHeader.nna & 3];
  823. mptIns->nDCT = DCT[(insHeader.nna >> 8) & 3];
  824. mptIns->nDNA = DNA[(insHeader.nna >> 12) & 3];
  825. // Load envelopes
  826. for(uint32 env = 0; env < 4; env++)
  827. {
  828. if(envMask & 1)
  829. {
  830. MT2IEnvelope mt2Env;
  831. instrChunk.ReadStruct(mt2Env);
  832. const EnvelopeType envType[4] = { ENV_VOLUME, ENV_PANNING, ENV_PITCH, ENV_PITCH };
  833. InstrumentEnvelope &mptEnv = mptIns->GetEnvelope(envType[env]);
  834. mptEnv.dwFlags.set(ENV_FILTER, (env == 3) && (mt2Env.flags & 1) != 0);
  835. mptEnv.dwFlags.set(ENV_ENABLED, (mt2Env.flags & 1) != 0);
  836. mptEnv.dwFlags.set(ENV_SUSTAIN, (mt2Env.flags & 2) != 0);
  837. mptEnv.dwFlags.set(ENV_LOOP, (mt2Env.flags & 4) != 0);
  838. mptEnv.resize(std::min(mt2Env.numPoints.get(), uint8(16)));
  839. mptEnv.nSustainStart = mptEnv.nSustainEnd = mt2Env.sustainPos;
  840. mptEnv.nLoopStart = mt2Env.loopStart;
  841. mptEnv.nLoopEnd = mt2Env.loopEnd;
  842. for(uint32 p = 0; p < mptEnv.size(); p++)
  843. {
  844. mptEnv[p].tick = mt2Env.points[p].x;
  845. mptEnv[p].value = static_cast<uint8>(Clamp<uint16, uint16>(mt2Env.points[p].y, 0, 64));
  846. }
  847. }
  848. envMask >>= 1;
  849. }
  850. if(!mptIns->VolEnv.dwFlags[ENV_ENABLED] && mptIns->nNNA != NewNoteAction::NoteFade)
  851. {
  852. mptIns->nFadeOut = int16_max;
  853. }
  854. mptIns->SetCutoff(0x7F, true);
  855. mptIns->SetResonance(0, true);
  856. if(flags)
  857. {
  858. MT2InstrSynth synthData;
  859. instrChunk.ReadStruct(synthData);
  860. if(flags & 2)
  861. {
  862. mptIns->SetCutoff(FrequencyToCutOff(synthData.cutoff), true);
  863. mptIns->SetResonance(synthData.resonance, true);
  864. }
  865. mptIns->filterMode = synthData.effectID == 1 ? FilterMode::HighPass : FilterMode::LowPass;
  866. if(flags & 4)
  867. {
  868. // VSTi / MIDI synth enabled
  869. mptIns->nMidiChannel = synthData.midiChannel + 1;
  870. mptIns->nMixPlug = static_cast<PLUGINDEX>(synthData.device + 1);
  871. if(synthData.device < 0)
  872. {
  873. // TODO: This is a MIDI device - maybe use MIDI I/O plugin to emulate those?
  874. mptIns->nMidiProgram = synthData.midiProgram + 1; // MT2 only seems to use this for MIDI devices, not VSTis!
  875. }
  876. if(synthData.transpose)
  877. {
  878. for(uint32 n = 0; n < std::size(mptIns->NoteMap); n++)
  879. {
  880. int note = NOTE_MIN + n + synthData.transpose;
  881. Limit(note, NOTE_MIN, NOTE_MAX);
  882. mptIns->NoteMap[n] = static_cast<uint8>(note);
  883. }
  884. }
  885. // Instruments with plugin assignments never play samples at the same time!
  886. mptIns->AssignSample(0);
  887. }
  888. }
  889. }
  890. // Read sample headers
  891. std::bitset<256> sampleNoInterpolation;
  892. std::bitset<256> sampleSynchronized;
  893. for(SAMPLEINDEX i = 0; i < 256; i++)
  894. {
  895. char sampleName[32];
  896. file.ReadArray(sampleName);
  897. uint32 dataLength = file.ReadUint32LE();
  898. FileReader sampleChunk = file.ReadChunk(dataLength);
  899. if(i < fileHeader.numSamples)
  900. {
  901. m_szNames[i + 1] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleName);
  902. }
  903. if(dataLength && i < fileHeader.numSamples)
  904. {
  905. ModSample &mptSmp = Samples[i + 1];
  906. mptSmp.Initialize(MOD_TYPE_IT);
  907. mptSmp.SetDefaultCuePoints();
  908. MT2Sample sampleHeader;
  909. sampleChunk.ReadStruct(sampleHeader);
  910. mptSmp.nLength = sampleHeader.length;
  911. mptSmp.nC5Speed = sampleHeader.frequency;
  912. if(sampleHeader.depth > 1) { mptSmp.uFlags.set(CHN_16BIT); mptSmp.nLength /= 2u; }
  913. if(sampleHeader.channels > 1) { mptSmp.uFlags.set(CHN_STEREO); mptSmp.nLength /= 2u; }
  914. if(sampleHeader.loopType == 1) mptSmp.uFlags.set(CHN_LOOP);
  915. else if(sampleHeader.loopType == 2) mptSmp.uFlags.set(CHN_LOOP | CHN_PINGPONGLOOP);
  916. mptSmp.nLoopStart = sampleHeader.loopStart;
  917. mptSmp.nLoopEnd = sampleHeader.loopEnd;
  918. mptSmp.nVolume = sampleHeader.volume >> 7;
  919. if(sampleHeader.panning == -128)
  920. mptSmp.uFlags.set(CHN_SURROUND);
  921. else
  922. mptSmp.nPan = sampleHeader.panning + 128;
  923. mptSmp.uFlags.set(CHN_PANNING);
  924. mptSmp.RelativeTone = sampleHeader.note;
  925. if(sampleHeader.flags & 2)
  926. {
  927. // Sample is synchronized to beat
  928. // The synchronization part is not supported in OpenMPT, but synchronized samples also always play at the same pitch as C-5, which we CAN do!
  929. sampleSynchronized[i] = true;
  930. //mptSmp.nC5Speed = Util::muldiv(mptSmp.nC5Speed, sampleHeader.spb, 22050);
  931. }
  932. if(sampleHeader.flags & 5)
  933. {
  934. // External sample
  935. mptSmp.uFlags.set(SMP_KEEPONDISK);
  936. }
  937. if(sampleHeader.flags & 8)
  938. {
  939. sampleNoInterpolation[i] = true;
  940. for(INSTRUMENTINDEX drum = 0; drum < 8; drum++)
  941. {
  942. if(drumSample[drum] == i && Instruments[drumMap[drum]] != nullptr)
  943. {
  944. Instruments[drumMap[drum]]->resampling = SRCMODE_NEAREST;
  945. }
  946. }
  947. }
  948. }
  949. }
  950. // Read sample groups
  951. for(INSTRUMENTINDEX ins = 0; ins < fileHeader.numInstruments; ins++)
  952. {
  953. if(instrChunks[ins].GetLength())
  954. {
  955. FileReader &chunk = instrChunks[ins];
  956. MT2Instrument insHeader;
  957. chunk.Rewind();
  958. chunk.ReadStruct(insHeader);
  959. std::vector<MT2Group> groups;
  960. file.ReadVector(groups, insHeader.numSamples);
  961. ModInstrument *mptIns = Instruments[ins + 1];
  962. // Instruments with plugin assignments never play samples at the same time!
  963. if(mptIns == nullptr || mptIns->nMixPlug != 0)
  964. continue;
  965. mptIns->nGlobalVol = 32; // Compensate for extended dynamic range of drum instruments
  966. mptIns->AssignSample(0);
  967. for(uint32 note = 0; note < 96; note++)
  968. {
  969. if(insHeader.groupMap[note] < insHeader.numSamples)
  970. {
  971. const MT2Group &group = groups[insHeader.groupMap[note]];
  972. SAMPLEINDEX sample = group.sample + 1;
  973. mptIns->Keyboard[note + 11 + NOTE_MIN] = sample;
  974. if(sample > 0 && sample <= m_nSamples)
  975. {
  976. ModSample &mptSmp = Samples[sample];
  977. mptSmp.nVibType = static_cast<VibratoType>(insHeader.vibtype & 3); // In fact, MT2 only implements sine vibrato
  978. mptSmp.nVibSweep = insHeader.vibsweep;
  979. mptSmp.nVibDepth = insHeader.vibdepth;
  980. mptSmp.nVibRate = insHeader.vibrate;
  981. mptSmp.nGlobalVol = uint16(group.vol) * 2;
  982. mptSmp.nFineTune = group.pitch;
  983. if(sampleNoInterpolation[sample - 1])
  984. {
  985. mptIns->resampling = SRCMODE_NEAREST;
  986. }
  987. if(sampleSynchronized[sample - 1])
  988. {
  989. mptIns->NoteMap[note + 11 + NOTE_MIN] = NOTE_MIDDLEC;
  990. }
  991. }
  992. // TODO: volume, finetune for duplicated samples
  993. }
  994. }
  995. }
  996. }
  997. if(!(loadFlags & loadSampleData))
  998. return true;
  999. // Read sample data
  1000. for(SAMPLEINDEX i = 0; i < m_nSamples; i++)
  1001. {
  1002. ModSample &mptSmp = Samples[i + 1];
  1003. mptSmp.Transpose(-(mptSmp.RelativeTone - 49 - (mptSmp.nFineTune / 128.0)) / 12.0);
  1004. mptSmp.nFineTune = 0;
  1005. mptSmp.RelativeTone = 0;
  1006. if(!mptSmp.uFlags[SMP_KEEPONDISK])
  1007. {
  1008. SampleIO(
  1009. mptSmp.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit,
  1010. mptSmp.uFlags[CHN_STEREO] ? SampleIO::stereoSplit : SampleIO::mono,
  1011. SampleIO::littleEndian,
  1012. SampleIO::MT2)
  1013. .ReadSample(mptSmp, file);
  1014. } else
  1015. {
  1016. // External sample
  1017. const uint32 filenameSize = file.ReadUint32LE();
  1018. file.Skip(12); // Reserved
  1019. std::string filename;
  1020. file.ReadString<mpt::String::maybeNullTerminated>(filename, filenameSize);
  1021. mptSmp.filename = filename;
  1022. #if defined(MPT_EXTERNAL_SAMPLES)
  1023. if(filename.length() >= 2
  1024. && filename[0] != '\\' // Relative path on same drive
  1025. && filename[1] != ':') // Absolute path
  1026. {
  1027. // Relative path in same folder or sub folder
  1028. filename = ".\\" + filename;
  1029. }
  1030. SetSamplePath(i + 1, mpt::PathString::FromLocaleSilent(filename));
  1031. #elif !defined(LIBOPENMPT_BUILD_TEST)
  1032. AddToLog(LogWarning, MPT_UFORMAT("Loading external sample {} ('{}') failed: External samples are not supported.")(i + 1, mpt::ToUnicode(GetCharsetFile(), filename)));
  1033. #endif // MPT_EXTERNAL_SAMPLES
  1034. }
  1035. }
  1036. return true;
  1037. }
  1038. OPENMPT_NAMESPACE_END