1
0

Load_amf.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. * Load_amf.cpp
  3. * ------------
  4. * Purpose: AMF module loader
  5. * Notes : There are two types of AMF files, the ASYLUM Music Format (used in Crusader: No Remorse and Crusader: No Regret)
  6. * and Advanced Music Format (DSMI / Digital Sound And Music Interface, used in various games such as Pinball World).
  7. * Both module types are handled here.
  8. * Authors: Olivier Lapicque
  9. * OpenMPT Devs
  10. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  11. */
  12. #include "stdafx.h"
  13. #include "Loaders.h"
  14. #include <algorithm>
  15. OPENMPT_NAMESPACE_BEGIN
  16. // ASYLUM AMF File Header
  17. struct AsylumFileHeader
  18. {
  19. char signature[32];
  20. uint8 defaultSpeed;
  21. uint8 defaultTempo;
  22. uint8 numSamples;
  23. uint8 numPatterns;
  24. uint8 numOrders;
  25. uint8 restartPos;
  26. };
  27. MPT_BINARY_STRUCT(AsylumFileHeader, 38)
  28. // ASYLUM AMF Sample Header
  29. struct AsylumSampleHeader
  30. {
  31. char name[22];
  32. uint8le finetune;
  33. uint8le defaultVolume;
  34. int8le transpose;
  35. uint32le length;
  36. uint32le loopStart;
  37. uint32le loopLength;
  38. // Convert an AMF sample header to OpenMPT's internal sample header.
  39. void ConvertToMPT(ModSample &mptSmp) const
  40. {
  41. mptSmp.Initialize();
  42. mptSmp.nFineTune = MOD2XMFineTune(finetune);
  43. mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4u;
  44. mptSmp.RelativeTone = transpose;
  45. mptSmp.nLength = length;
  46. if(loopLength > 2 && loopStart + loopLength <= length)
  47. {
  48. mptSmp.uFlags.set(CHN_LOOP);
  49. mptSmp.nLoopStart = loopStart;
  50. mptSmp.nLoopEnd = loopStart + loopLength;
  51. }
  52. }
  53. };
  54. MPT_BINARY_STRUCT(AsylumSampleHeader, 37)
  55. static bool ValidateHeader(const AsylumFileHeader &fileHeader)
  56. {
  57. if(std::memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
  58. || fileHeader.numSamples > 64
  59. )
  60. {
  61. return false;
  62. }
  63. return true;
  64. }
  65. static uint64 GetHeaderMinimumAdditionalSize(const AsylumFileHeader &fileHeader)
  66. {
  67. return 256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns;
  68. }
  69. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize)
  70. {
  71. AsylumFileHeader fileHeader;
  72. if(!file.ReadStruct(fileHeader))
  73. {
  74. return ProbeWantMoreData;
  75. }
  76. if(!ValidateHeader(fileHeader))
  77. {
  78. return ProbeFailure;
  79. }
  80. return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
  81. }
  82. bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
  83. {
  84. file.Rewind();
  85. AsylumFileHeader fileHeader;
  86. if(!file.ReadStruct(fileHeader))
  87. {
  88. return false;
  89. }
  90. if(!ValidateHeader(fileHeader))
  91. {
  92. return false;
  93. }
  94. if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
  95. {
  96. return false;
  97. }
  98. if(loadFlags == onlyVerifyHeader)
  99. {
  100. return true;
  101. }
  102. InitializeGlobals(MOD_TYPE_AMF0);
  103. InitializeChannels();
  104. SetupMODPanning(true);
  105. m_nChannels = 8;
  106. m_nDefaultSpeed = fileHeader.defaultSpeed;
  107. m_nDefaultTempo.Set(fileHeader.defaultTempo);
  108. m_nSamples = fileHeader.numSamples;
  109. if(fileHeader.restartPos < fileHeader.numOrders)
  110. {
  111. Order().SetRestartPos(fileHeader.restartPos);
  112. }
  113. m_modFormat.formatName = U_("ASYLUM Music Format");
  114. m_modFormat.type = U_("amf");
  115. m_modFormat.charset = mpt::Charset::CP437;
  116. uint8 orders[256];
  117. file.ReadArray(orders);
  118. ReadOrderFromArray(Order(), orders, fileHeader.numOrders);
  119. // Read Sample Headers
  120. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
  121. {
  122. AsylumSampleHeader sampleHeader;
  123. file.ReadStruct(sampleHeader);
  124. sampleHeader.ConvertToMPT(Samples[smp]);
  125. m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name);
  126. }
  127. file.Skip((64 - fileHeader.numSamples) * sizeof(AsylumSampleHeader));
  128. // Read Patterns
  129. Patterns.ResizeArray(fileHeader.numPatterns);
  130. for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
  131. {
  132. if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
  133. {
  134. file.Skip(64 * 4 * 8);
  135. continue;
  136. }
  137. for(auto &m : Patterns[pat])
  138. {
  139. const auto [note, instr, command, param] = file.ReadArray<uint8, 4>();
  140. if(note && note + 12 + NOTE_MIN <= NOTE_MAX)
  141. {
  142. m.note = note + 12 + NOTE_MIN;
  143. }
  144. m.instr = instr;
  145. m.command = command;
  146. m.param = param;
  147. ConvertModCommand(m);
  148. #ifdef MODPLUG_TRACKER
  149. if(m.command == CMD_PANNING8)
  150. {
  151. // Convert 7-bit panning to 8-bit
  152. m.param = mpt::saturate_cast<ModCommand::PARAM>(m.param * 2u);
  153. }
  154. #endif
  155. }
  156. }
  157. if(loadFlags & loadSampleData)
  158. {
  159. // Read Sample Data
  160. const SampleIO sampleIO(
  161. SampleIO::_8bit,
  162. SampleIO::mono,
  163. SampleIO::littleEndian,
  164. SampleIO::signedPCM);
  165. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
  166. {
  167. sampleIO.ReadSample(Samples[smp], file);
  168. }
  169. }
  170. return true;
  171. }
  172. // DSMI AMF File Header
  173. struct AMFFileHeader
  174. {
  175. char amf[3];
  176. uint8le version;
  177. char title[32];
  178. uint8le numSamples;
  179. uint8le numOrders;
  180. uint16le numTracks;
  181. uint8le numChannels;
  182. };
  183. MPT_BINARY_STRUCT(AMFFileHeader, 41)
  184. // DSMI AMF Sample Header (v1-v9)
  185. struct AMFSampleHeaderOld
  186. {
  187. uint8le type;
  188. char name[32];
  189. char filename[13];
  190. uint32le index;
  191. uint16le length;
  192. uint16le sampleRate;
  193. uint8le volume;
  194. uint16le loopStart;
  195. uint16le loopEnd;
  196. void ConvertToMPT(ModSample &mptSmp) const
  197. {
  198. mptSmp.Initialize();
  199. mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename);
  200. mptSmp.nLength = length;
  201. mptSmp.nC5Speed = sampleRate;
  202. mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u;
  203. mptSmp.nLoopStart = loopStart;
  204. mptSmp.nLoopEnd = loopEnd;
  205. if(mptSmp.nLoopEnd == uint16_max)
  206. mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
  207. else if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength)
  208. mptSmp.uFlags.set(CHN_LOOP);
  209. }
  210. };
  211. MPT_BINARY_STRUCT(AMFSampleHeaderOld, 59)
  212. // DSMI AMF Sample Header (v10+)
  213. struct AMFSampleHeaderNew
  214. {
  215. uint8le type;
  216. char name[32];
  217. char filename[13];
  218. uint32le index;
  219. uint32le length;
  220. uint16le sampleRate;
  221. uint8le volume;
  222. uint32le loopStart;
  223. uint32le loopEnd;
  224. void ConvertToMPT(ModSample &mptSmp, bool truncated) const
  225. {
  226. mptSmp.Initialize();
  227. mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename);
  228. mptSmp.nLength = length;
  229. mptSmp.nC5Speed = sampleRate;
  230. mptSmp.nVolume = std::min(volume.get(), uint8(64)) * 4u;
  231. mptSmp.nLoopStart = loopStart;
  232. mptSmp.nLoopEnd = loopEnd;
  233. if(truncated && mptSmp.nLoopStart > 0)
  234. mptSmp.nLoopEnd = mptSmp.nLength;
  235. if(type != 0 && mptSmp.nLoopEnd > mptSmp.nLoopStart + 2 && mptSmp.nLoopEnd <= mptSmp.nLength)
  236. mptSmp.uFlags.set(CHN_LOOP);
  237. }
  238. // Check if sample headers might be truncated
  239. bool IsValid(uint8 numSamples) const
  240. {
  241. return type <= 1 && index <= numSamples && length <= 0x100000 && volume <= 64 && loopStart <= length && loopEnd <= length;
  242. }
  243. };
  244. MPT_BINARY_STRUCT(AMFSampleHeaderNew, 65)
  245. // Read a single AMF track (channel) into a pattern.
  246. static void AMFReadPattern(CPattern &pattern, CHANNELINDEX chn, FileReader &fileChunk)
  247. {
  248. fileChunk.Rewind();
  249. while(fileChunk.CanRead(3))
  250. {
  251. const auto [row, command, value] = fileChunk.ReadArray<uint8, 3>();
  252. if(row >= pattern.GetNumRows())
  253. {
  254. break;
  255. }
  256. ModCommand &m = *pattern.GetpModCommand(row, chn);
  257. if(command < 0x7F)
  258. {
  259. // Note + Volume
  260. if(command == 0 && value == 0)
  261. {
  262. m.note = NOTE_NOTECUT;
  263. } else
  264. {
  265. m.note = command + NOTE_MIN;
  266. if(value != 0xFF)
  267. {
  268. m.volcmd = VOLCMD_VOLUME;
  269. m.vol = value;
  270. }
  271. }
  272. } else if(command == 0x7F)
  273. {
  274. // Instrument without note retrigger in MOD (no need to do anything here, should be preceded by 0x80 command)
  275. } else if(command == 0x80)
  276. {
  277. // Instrument
  278. m.instr = value + 1;
  279. } else
  280. {
  281. // Effect
  282. static constexpr ModCommand::COMMAND effTrans[] =
  283. {
  284. CMD_NONE, CMD_SPEED, CMD_VOLUMESLIDE, CMD_VOLUME,
  285. CMD_PORTAMENTOUP, CMD_NONE, CMD_TONEPORTAMENTO, CMD_TREMOR,
  286. CMD_ARPEGGIO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL,
  287. CMD_PATTERNBREAK, CMD_POSITIONJUMP, CMD_NONE, CMD_RETRIG,
  288. CMD_OFFSET, CMD_VOLUMESLIDE, CMD_PORTAMENTOUP, CMD_S3MCMDEX,
  289. CMD_S3MCMDEX, CMD_TEMPO, CMD_PORTAMENTOUP, CMD_PANNING8,
  290. };
  291. uint8 cmd = (command & 0x7F);
  292. uint8 param = value;
  293. if(cmd < std::size(effTrans))
  294. cmd = effTrans[cmd];
  295. else
  296. cmd = CMD_NONE;
  297. // Fix some commands...
  298. switch(command & 0x7F)
  299. {
  300. // 02: Volume Slide
  301. // 0A: Tone Porta + Vol Slide
  302. // 0B: Vibrato + Vol Slide
  303. case 0x02:
  304. case 0x0A:
  305. case 0x0B:
  306. if(param & 0x80)
  307. param = (-static_cast<int8>(param)) & 0x0F;
  308. else
  309. param = (param & 0x0F) << 4;
  310. break;
  311. // 03: Volume
  312. case 0x03:
  313. param = std::min(param, uint8(64));
  314. if(m.volcmd == VOLCMD_NONE || m.volcmd == VOLCMD_VOLUME)
  315. {
  316. m.volcmd = VOLCMD_VOLUME;
  317. m.vol = param;
  318. cmd = CMD_NONE;
  319. }
  320. break;
  321. // 04: Porta Up/Down
  322. case 0x04:
  323. if(param & 0x80)
  324. param = (-static_cast<int8>(param)) & 0x7F;
  325. else
  326. cmd = CMD_PORTAMENTODOWN;
  327. break;
  328. // 11: Fine Volume Slide
  329. case 0x11:
  330. if(param)
  331. {
  332. if(param & 0x80)
  333. param = 0xF0 | ((-static_cast<int8>(param)) & 0x0F);
  334. else
  335. param = 0x0F | ((param & 0x0F) << 4);
  336. } else
  337. {
  338. cmd = CMD_NONE;
  339. }
  340. break;
  341. // 12: Fine Portamento
  342. // 16: Extra Fine Portamento
  343. case 0x12:
  344. case 0x16:
  345. if(param)
  346. {
  347. cmd = static_cast<uint8>((param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN);
  348. if(param & 0x80)
  349. {
  350. param = ((-static_cast<int8>(param)) & 0x0F);
  351. }
  352. param |= (command == 0x16) ? 0xE0 : 0xF0;
  353. } else
  354. {
  355. cmd = CMD_NONE;
  356. }
  357. break;
  358. // 13: Note Delay
  359. case 0x13:
  360. param = 0xD0 | (param & 0x0F);
  361. break;
  362. // 14: Note Cut
  363. case 0x14:
  364. param = 0xC0 | (param & 0x0F);
  365. break;
  366. // 17: Panning
  367. case 0x17:
  368. if(param == 100)
  369. {
  370. // History lesson intermission: According to Otto Chrons, he remembers that he added support
  371. // for 8A4 / XA4 "surround" panning in DMP for MOD and S3M files before any other trackers did,
  372. // So DSMI / DMP are most likely the original source of these 7-bit panning + surround commands!
  373. param = 0xA4;
  374. } else
  375. {
  376. param = static_cast<uint8>(std::clamp(static_cast<int8>(param) + 64, 0, 128));
  377. if(m.command != CMD_NONE)
  378. {
  379. // Move to volume column if required
  380. if(m.volcmd == VOLCMD_NONE || m.volcmd == VOLCMD_PANNING)
  381. {
  382. m.volcmd = VOLCMD_PANNING;
  383. m.vol = param / 2;
  384. }
  385. cmd = CMD_NONE;
  386. }
  387. }
  388. break;
  389. }
  390. if(cmd != CMD_NONE)
  391. {
  392. m.command = cmd;
  393. m.param = param;
  394. }
  395. }
  396. }
  397. }
  398. static bool ValidateHeader(const AMFFileHeader &fileHeader)
  399. {
  400. if(std::memcmp(fileHeader.amf, "AMF", 3)
  401. || (fileHeader.version < 8 && fileHeader.version != 1) || fileHeader.version > 14
  402. || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 9))
  403. {
  404. return false;
  405. }
  406. return true;
  407. }
  408. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize)
  409. {
  410. AMFFileHeader fileHeader;
  411. if(!file.ReadStruct(fileHeader))
  412. {
  413. return ProbeWantMoreData;
  414. }
  415. if(!ValidateHeader(fileHeader))
  416. {
  417. return ProbeFailure;
  418. }
  419. MPT_UNREFERENCED_PARAMETER(pfilesize);
  420. return ProbeSuccess;
  421. }
  422. bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
  423. {
  424. file.Rewind();
  425. AMFFileHeader fileHeader;
  426. if(!file.ReadStruct(fileHeader))
  427. {
  428. return false;
  429. }
  430. if(!ValidateHeader(fileHeader))
  431. {
  432. return false;
  433. }
  434. if(loadFlags == onlyVerifyHeader)
  435. {
  436. return true;
  437. }
  438. InitializeGlobals(MOD_TYPE_AMF);
  439. InitializeChannels();
  440. m_modFormat.formatName = MPT_UFORMAT("DSMI v{}")(fileHeader.version);
  441. m_modFormat.type = U_("amf");
  442. m_modFormat.charset = mpt::Charset::CP437;
  443. m_nChannels = fileHeader.numChannels;
  444. m_nSamples = fileHeader.numSamples;
  445. m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.title);
  446. if(fileHeader.version < 9)
  447. {
  448. // Old format revisions are fixed to 4 channels
  449. m_nChannels = 4;
  450. file.SkipBack(1);
  451. SetupMODPanning(true);
  452. }
  453. // Setup Channel Pan Positions
  454. if(fileHeader.version >= 11)
  455. {
  456. const CHANNELINDEX readChannels = fileHeader.version >= 12 ? 32 : 16;
  457. for(CHANNELINDEX chn = 0; chn < readChannels; chn++)
  458. {
  459. int8 pan = file.ReadInt8();
  460. if(pan == 100)
  461. ChnSettings[chn].dwFlags = CHN_SURROUND;
  462. else
  463. ChnSettings[chn].nPan = static_cast<uint16>(std::clamp((pan + 64) * 2, 0, 256));
  464. }
  465. } else if(fileHeader.version >= 9)
  466. {
  467. uint8 panPos[16];
  468. file.ReadArray(panPos);
  469. for(CHANNELINDEX chn = 0; chn < 16; chn++)
  470. {
  471. ChnSettings[chn].nPan = (panPos[chn] & 1) ? 0x40 : 0xC0;
  472. }
  473. }
  474. // Get Tempo/Speed
  475. if(fileHeader.version >= 13)
  476. {
  477. auto [tempo, speed] = file.ReadArray<uint8, 2>();
  478. if(tempo < 32)
  479. tempo = 125;
  480. m_nDefaultTempo.Set(tempo);
  481. m_nDefaultSpeed = speed;
  482. } else
  483. {
  484. m_nDefaultTempo.Set(125);
  485. m_nDefaultSpeed = 6;
  486. }
  487. // Setup Order List
  488. Order().resize(fileHeader.numOrders);
  489. std::vector<uint16> patternLength;
  490. const FileReader::off_t trackStartPos = file.GetPosition() + (fileHeader.version >= 14 ? 2 : 0);
  491. if(fileHeader.version >= 14)
  492. {
  493. patternLength.resize(fileHeader.numOrders);
  494. }
  495. for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++)
  496. {
  497. Order()[ord] = ord;
  498. if(fileHeader.version >= 14)
  499. {
  500. patternLength[ord] = file.ReadUint16LE();
  501. }
  502. // Track positions will be read as needed.
  503. file.Skip(m_nChannels * 2);
  504. }
  505. // Read Sample Headers
  506. bool truncatedSampleHeaders = false;
  507. if(fileHeader.version == 10)
  508. {
  509. // M2AMF 1.3 included with DMP 2.32 wrote new (v10+) sample headers, but using the old struct length.
  510. const auto startPos = file.GetPosition();
  511. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
  512. {
  513. AMFSampleHeaderNew sample;
  514. if(file.ReadStruct(sample) && !sample.IsValid(fileHeader.numSamples))
  515. {
  516. truncatedSampleHeaders = true;
  517. break;
  518. }
  519. }
  520. file.Seek(startPos);
  521. }
  522. std::vector<uint32> sampleMap(GetNumSamples(), 0);
  523. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
  524. {
  525. if(fileHeader.version < 10)
  526. {
  527. AMFSampleHeaderOld sample;
  528. file.ReadStruct(sample);
  529. sample.ConvertToMPT(Samples[smp]);
  530. m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sample.name);
  531. sampleMap[smp - 1] = sample.index;
  532. } else
  533. {
  534. AMFSampleHeaderNew sample;
  535. file.ReadStructPartial(sample, truncatedSampleHeaders ? sizeof(AMFSampleHeaderOld) : sizeof(AMFSampleHeaderNew));
  536. sample.ConvertToMPT(Samples[smp], truncatedSampleHeaders);
  537. m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sample.name);
  538. sampleMap[smp - 1] = sample.index;
  539. }
  540. }
  541. // Read Track Mapping Table
  542. std::vector<uint16le> trackMap;
  543. if(!file.ReadVector(trackMap, fileHeader.numTracks))
  544. {
  545. return false;
  546. }
  547. uint16 trackCount = 0;
  548. if(!trackMap.empty())
  549. trackCount = *std::max_element(trackMap.cbegin(), trackMap.cend());
  550. // Read pattern tracks
  551. std::vector<FileReader> trackData(trackCount);
  552. for(uint16 i = 0; i < trackCount; i++)
  553. {
  554. // Track size is a 16-Bit value describing the number of byte triplets in this track, followed by a track type byte.
  555. uint16 numEvents = file.ReadUint16LE();
  556. file.Skip(1);
  557. if(numEvents)
  558. trackData[i] = file.ReadChunk(numEvents * 3 + (fileHeader.version == 1 ? 3 : 0));
  559. }
  560. if(loadFlags & loadSampleData)
  561. {
  562. // Read Sample Data
  563. const SampleIO sampleIO(
  564. SampleIO::_8bit,
  565. SampleIO::mono,
  566. SampleIO::littleEndian,
  567. SampleIO::unsignedPCM);
  568. // Note: in theory a sample can be reused by several instruments and appear in a different order in the file
  569. // However, M2AMF doesn't take advantage of this and just writes instruments in the order they appear,
  570. // without de-duplicating identical sample data.
  571. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples() && file.CanRead(1); smp++)
  572. {
  573. auto startPos = file.GetPosition();
  574. for(SAMPLEINDEX target = 0; target < GetNumSamples(); target++)
  575. {
  576. if(sampleMap[target] != smp)
  577. continue;
  578. file.Seek(startPos);
  579. sampleIO.ReadSample(Samples[target + 1], file);
  580. }
  581. }
  582. }
  583. if(!(loadFlags & loadPatternData))
  584. {
  585. return true;
  586. }
  587. // Create the patterns from the list of tracks
  588. Patterns.ResizeArray(fileHeader.numOrders);
  589. for(PATTERNINDEX pat = 0; pat < fileHeader.numOrders; pat++)
  590. {
  591. uint16 patLength = pat < patternLength.size() ? patternLength[pat] : 64;
  592. if(!Patterns.Insert(pat, patLength))
  593. {
  594. continue;
  595. }
  596. // Get table with per-channel track assignments
  597. file.Seek(trackStartPos + pat * (GetNumChannels() * 2 + (fileHeader.version >= 14 ? 2 : 0)));
  598. std::vector<uint16le> tracks;
  599. if(!file.ReadVector(tracks, GetNumChannels()))
  600. {
  601. continue;
  602. }
  603. for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
  604. {
  605. if(tracks[chn] > 0 && tracks[chn] <= fileHeader.numTracks)
  606. {
  607. uint16 realTrack = trackMap[tracks[chn] - 1];
  608. if(realTrack > 0 && realTrack <= trackCount)
  609. {
  610. realTrack--;
  611. AMFReadPattern(Patterns[pat], chn, trackData[realTrack]);
  612. }
  613. }
  614. }
  615. }
  616. return true;
  617. }
  618. OPENMPT_NAMESPACE_END