Load_imf.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /*
  2. * Load_imf.cpp
  3. * ------------
  4. * Purpose: IMF (Imago Orpheus) module loader
  5. * Notes : Reverb and Chorus are not supported.
  6. * Authors: Storlek (Original author - http://schismtracker.org/ - code ported with permission)
  7. * Johannes Schultz (OpenMPT Port, tweaks)
  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. OPENMPT_NAMESPACE_BEGIN
  13. struct IMFChannel
  14. {
  15. char name[12]; // Channel name (ASCIIZ-String, max 11 chars)
  16. uint8 chorus; // Default chorus
  17. uint8 reverb; // Default reverb
  18. uint8 panning; // Pan positions 00-FF
  19. uint8 status; // Channel status: 0 = enabled, 1 = mute, 2 = disabled (ignore effects!)
  20. };
  21. MPT_BINARY_STRUCT(IMFChannel, 16)
  22. struct IMFFileHeader
  23. {
  24. enum SongFlags
  25. {
  26. linearSlides = 0x01,
  27. };
  28. char title[32]; // Songname (ASCIIZ-String, max. 31 chars)
  29. uint16le ordNum; // Number of orders saved
  30. uint16le patNum; // Number of patterns saved
  31. uint16le insNum; // Number of instruments saved
  32. uint16le flags; // See SongFlags
  33. uint8le unused1[8];
  34. uint8le tempo; // Default tempo (Axx, 1...255)
  35. uint8le bpm; // Default beats per minute (BPM) (Txx, 32...255)
  36. uint8le master; // Default master volume (Vxx, 0...64)
  37. uint8le amp; // Amplification factor (mixing volume, 4...127)
  38. uint8le unused2[8];
  39. char im10[4]; // 'IM10'
  40. IMFChannel channels[32]; // Channel settings
  41. };
  42. MPT_BINARY_STRUCT(IMFFileHeader, 576)
  43. struct IMFEnvelope
  44. {
  45. enum EnvFlags
  46. {
  47. envEnabled = 0x01,
  48. envSustain = 0x02,
  49. envLoop = 0x04,
  50. };
  51. uint8 points; // Number of envelope points
  52. uint8 sustain; // Envelope sustain point
  53. uint8 loopStart; // Envelope loop start point
  54. uint8 loopEnd; // Envelope loop end point
  55. uint8 flags; // See EnvFlags
  56. uint8 unused[3];
  57. };
  58. MPT_BINARY_STRUCT(IMFEnvelope, 8)
  59. struct IMFEnvNode
  60. {
  61. uint16le tick;
  62. uint16le value;
  63. };
  64. MPT_BINARY_STRUCT(IMFEnvNode, 4)
  65. struct IMFInstrument
  66. {
  67. enum EnvTypes
  68. {
  69. volEnv = 0,
  70. panEnv = 1,
  71. filterEnv = 2,
  72. };
  73. char name[32]; // Inst. name (ASCIIZ-String, max. 31 chars)
  74. uint8le map[120]; // Multisample settings
  75. uint8le unused[8];
  76. IMFEnvNode nodes[3][16];
  77. IMFEnvelope env[3];
  78. uint16le fadeout; // Fadeout rate (0...0FFFH)
  79. uint16le smpNum; // Number of samples in instrument
  80. char ii10[4]; // 'II10' (not verified by Orpheus)
  81. void ConvertEnvelope(InstrumentEnvelope &mptEnv, EnvTypes e) const
  82. {
  83. const uint8 shift = (e == volEnv) ? 0 : 2;
  84. const uint8 mirror = (e == filterEnv) ? 0xFF : 0x00;
  85. mptEnv.dwFlags.set(ENV_ENABLED, (env[e].flags & 1) != 0);
  86. mptEnv.dwFlags.set(ENV_SUSTAIN, (env[e].flags & 2) != 0);
  87. mptEnv.dwFlags.set(ENV_LOOP, (env[e].flags & 4) != 0);
  88. mptEnv.resize(Clamp(env[e].points, uint8(2), uint8(16)));
  89. mptEnv.nLoopStart = env[e].loopStart;
  90. mptEnv.nLoopEnd = env[e].loopEnd;
  91. mptEnv.nSustainStart = mptEnv.nSustainEnd = env[e].sustain;
  92. uint16 minTick = 0; // minimum tick value for next node
  93. for(uint32 n = 0; n < mptEnv.size(); n++)
  94. {
  95. mptEnv[n].tick = minTick = std::max(minTick, nodes[e][n].tick.get());
  96. minTick++;
  97. uint8 value = static_cast<uint8>(nodes[e][n].value ^ mirror) >> shift;
  98. mptEnv[n].value = std::min(value, uint8(ENVELOPE_MAX));
  99. }
  100. mptEnv.Convert(MOD_TYPE_XM, MOD_TYPE_IT);
  101. }
  102. // Convert an IMFInstrument to OpenMPT's internal instrument representation.
  103. void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX firstSample) const
  104. {
  105. mptIns.name = mpt::String::ReadBuf(mpt::String::nullTerminated, name);
  106. if(smpNum)
  107. {
  108. for(size_t note = 0; note < std::min(std::size(map), std::size(mptIns.Keyboard) - 12u); note++)
  109. {
  110. mptIns.Keyboard[note + 12] = firstSample + map[note];
  111. }
  112. }
  113. mptIns.nFadeOut = fadeout;
  114. mptIns.midiPWD = 1; // For CMD_FINETUNE
  115. ConvertEnvelope(mptIns.VolEnv, volEnv);
  116. ConvertEnvelope(mptIns.PanEnv, panEnv);
  117. ConvertEnvelope(mptIns.PitchEnv, filterEnv);
  118. if(mptIns.PitchEnv.dwFlags[ENV_ENABLED])
  119. mptIns.PitchEnv.dwFlags.set(ENV_FILTER);
  120. // hack to get === to stop notes
  121. if(!mptIns.VolEnv.dwFlags[ENV_ENABLED] && !mptIns.nFadeOut)
  122. mptIns.nFadeOut = 32767;
  123. }
  124. };
  125. MPT_BINARY_STRUCT(IMFInstrument, 384)
  126. struct IMFSample
  127. {
  128. enum SampleFlags
  129. {
  130. smpLoop = 0x01,
  131. smpPingPongLoop = 0x02,
  132. smp16Bit = 0x04,
  133. smpPanning = 0x08,
  134. };
  135. char filename[13]; // Sample filename (12345678.ABC) */
  136. uint8le unused1[3];
  137. uint32le length; // Length (in bytes)
  138. uint32le loopStart; // Loop start (in bytes)
  139. uint32le loopEnd; // Loop end (in bytes)
  140. uint32le c5Speed; // Samplerate
  141. uint8le volume; // Default volume (0...64)
  142. uint8le panning; // Default pan (0...255)
  143. uint8le unused2[14];
  144. uint8le flags; // Sample flags
  145. uint8le unused3[5];
  146. uint16le ems; // Reserved for internal usage
  147. uint32le dram; // Reserved for internal usage
  148. char is10[4]; // 'IS10'
  149. // Convert an IMFSample to OpenMPT's internal sample representation.
  150. void ConvertToMPT(ModSample &mptSmp) const
  151. {
  152. mptSmp.Initialize();
  153. mptSmp.filename = mpt::String::ReadBuf(mpt::String::nullTerminated, filename);
  154. mptSmp.nLength = length;
  155. mptSmp.nLoopStart = loopStart;
  156. mptSmp.nLoopEnd = loopEnd;
  157. mptSmp.nC5Speed = c5Speed;
  158. mptSmp.nVolume = volume * 4;
  159. mptSmp.nPan = panning;
  160. if(flags & smpLoop)
  161. mptSmp.uFlags.set(CHN_LOOP);
  162. if(flags & smpPingPongLoop)
  163. mptSmp.uFlags.set(CHN_PINGPONGLOOP);
  164. if(flags & smp16Bit)
  165. {
  166. mptSmp.uFlags.set(CHN_16BIT);
  167. mptSmp.nLength /= 2;
  168. mptSmp.nLoopStart /= 2;
  169. mptSmp.nLoopEnd /= 2;
  170. }
  171. if(flags & smpPanning)
  172. mptSmp.uFlags.set(CHN_PANNING);
  173. }
  174. };
  175. MPT_BINARY_STRUCT(IMFSample, 64)
  176. static constexpr EffectCommand imfEffects[] =
  177. {
  178. CMD_NONE,
  179. CMD_SPEED, // 0x01 1xx Set Tempo
  180. CMD_TEMPO, // 0x02 2xx Set BPM
  181. CMD_TONEPORTAMENTO, // 0x03 3xx Tone Portamento
  182. CMD_TONEPORTAVOL, // 0x04 4xy Tone Portamento + Volume Slide
  183. CMD_VIBRATO, // 0x05 5xy Vibrato
  184. CMD_VIBRATOVOL, // 0x06 6xy Vibrato + Volume Slide
  185. CMD_FINEVIBRATO, // 0x07 7xy Fine Vibrato
  186. CMD_TREMOLO, // 0x08 8xy Tremolo
  187. CMD_ARPEGGIO, // 0x09 9xy Arpeggio
  188. CMD_PANNING8, // 0x0A Axx Set Pan Position
  189. CMD_PANNINGSLIDE, // 0x0B Bxy Pan Slide
  190. CMD_VOLUME, // 0x0C Cxx Set Volume
  191. CMD_VOLUMESLIDE, // 0x0D Dxy Volume Slide
  192. CMD_VOLUMESLIDE, // 0x0E Exy Fine Volume Slide
  193. CMD_FINETUNE, // 0x0F Fxx Set Finetune
  194. CMD_NOTESLIDEUP, // 0x10 Gxy Note Slide Up
  195. CMD_NOTESLIDEDOWN, // 0x11 Hxy Note Slide Down
  196. CMD_PORTAMENTOUP, // 0x12 Ixx Slide Up
  197. CMD_PORTAMENTODOWN, // 0x13 Jxx Slide Down
  198. CMD_PORTAMENTOUP, // 0x14 Kxx Fine Slide Up
  199. CMD_PORTAMENTODOWN, // 0x15 Lxx Fine Slide Down
  200. CMD_MIDI, // 0x16 Mxx Set Filter Cutoff
  201. CMD_MIDI, // 0x17 Nxy Filter Slide + Resonance
  202. CMD_OFFSET, // 0x18 Oxx Set Sample Offset
  203. CMD_NONE, // 0x19 Pxx Set Fine Sample Offset - XXX
  204. CMD_KEYOFF, // 0x1A Qxx Key Off
  205. CMD_RETRIG, // 0x1B Rxy Retrig
  206. CMD_TREMOR, // 0x1C Sxy Tremor
  207. CMD_POSITIONJUMP, // 0x1D Txx Position Jump
  208. CMD_PATTERNBREAK, // 0x1E Uxx Pattern Break
  209. CMD_GLOBALVOLUME, // 0x1F Vxx Set Mastervolume
  210. CMD_GLOBALVOLSLIDE, // 0x20 Wxy Mastervolume Slide
  211. CMD_S3MCMDEX, // 0x21 Xxx Extended Effect
  212. // X1x Set Filter
  213. // X3x Glissando
  214. // X5x Vibrato Waveform
  215. // X8x Tremolo Waveform
  216. // XAx Pattern Loop
  217. // XBx Pattern Delay
  218. // XCx Note Cut
  219. // XDx Note Delay
  220. // XEx Ignore Envelope
  221. // XFx Invert Loop
  222. CMD_NONE, // 0x22 Yxx Chorus - XXX
  223. CMD_NONE, // 0x23 Zxx Reverb - XXX
  224. };
  225. static void ImportIMFEffect(ModCommand &m)
  226. {
  227. uint8 n;
  228. // fix some of them
  229. switch(m.command)
  230. {
  231. case 0xE: // fine volslide
  232. // hackaround to get almost-right behavior for fine slides (i think!)
  233. if(m.param == 0)
  234. /* nothing */;
  235. else if(m.param == 0xF0)
  236. m.param = 0xEF;
  237. else if(m.param == 0x0F)
  238. m.param = 0xFE;
  239. else if(m.param & 0xF0)
  240. m.param |= 0x0F;
  241. else
  242. m.param |= 0xF0;
  243. break;
  244. case 0xF: // set finetune
  245. m.param ^= 0x80;
  246. break;
  247. case 0x14: // fine slide up
  248. case 0x15: // fine slide down
  249. // this is about as close as we can do...
  250. if(m.param >> 4)
  251. m.param = 0xF0 | (m.param >> 4);
  252. else
  253. m.param |= 0xE0;
  254. break;
  255. case 0x16: // cutoff
  256. m.param = (0xFF - m.param) / 2u;
  257. break;
  258. case 0x17: // cutoff slide + resonance (TODO: cutoff slide is currently not handled)
  259. m.param = 0x80 | (m.param & 0x0F);
  260. break;
  261. case 0x1F: // set global volume
  262. m.param = mpt::saturate_cast<uint8>(m.param * 2);
  263. break;
  264. case 0x21:
  265. n = 0;
  266. switch (m.param >> 4)
  267. {
  268. case 0:
  269. /* undefined, but since S0x does nothing in IT anyway, we won't care.
  270. this is here to allow S00 to pick up the previous value (assuming IMF
  271. even does that -- I haven't actually tried it) */
  272. break;
  273. default: // undefined
  274. case 0x1: // set filter
  275. case 0xF: // invert loop
  276. m.command = CMD_NONE;
  277. break;
  278. case 0x3: // glissando
  279. n = 0x20;
  280. break;
  281. case 0x5: // vibrato waveform
  282. n = 0x30;
  283. break;
  284. case 0x8: // tremolo waveform
  285. n = 0x40;
  286. break;
  287. case 0xA: // pattern loop
  288. n = 0xB0;
  289. break;
  290. case 0xB: // pattern delay
  291. n = 0xE0;
  292. break;
  293. case 0xC: // note cut
  294. case 0xD: // note delay
  295. // Apparently, Imago Orpheus doesn't cut samples on tick 0.
  296. if(!m.param)
  297. m.command = CMD_NONE;
  298. break;
  299. case 0xE: // ignore envelope
  300. switch(m.param & 0x0F)
  301. {
  302. // All envelopes
  303. // Predicament: we can only disable one envelope at a time. Volume is probably most noticeable, so let's go with that.
  304. case 0: m.param = 0x77; break;
  305. // Volume
  306. case 1: m.param = 0x77; break;
  307. // Panning
  308. case 2: m.param = 0x79; break;
  309. // Filter
  310. case 3: m.param = 0x7B; break;
  311. }
  312. break;
  313. case 0x18: // sample offset
  314. // O00 doesn't pick up the previous value
  315. if(!m.param)
  316. m.command = CMD_NONE;
  317. break;
  318. }
  319. if(n)
  320. m.param = n | (m.param & 0x0F);
  321. break;
  322. }
  323. m.command = (m.command < std::size(imfEffects)) ? imfEffects[m.command] : CMD_NONE;
  324. if(m.command == CMD_VOLUME && m.volcmd == VOLCMD_NONE)
  325. {
  326. m.volcmd = VOLCMD_VOLUME;
  327. m.vol = m.param;
  328. m.command = CMD_NONE;
  329. m.param = 0;
  330. }
  331. }
  332. static bool ValidateHeader(const IMFFileHeader &fileHeader)
  333. {
  334. if(std::memcmp(fileHeader.im10, "IM10", 4)
  335. || fileHeader.ordNum > 256
  336. || fileHeader.insNum >= MAX_INSTRUMENTS
  337. || fileHeader.bpm < 32
  338. || fileHeader.master > 64
  339. || fileHeader.amp < 4
  340. || fileHeader.amp > 127)
  341. {
  342. return false;
  343. }
  344. bool channelFound = false;
  345. for(const auto &chn : fileHeader.channels)
  346. {
  347. switch(chn.status)
  348. {
  349. case 0: // enabled; don't worry about it
  350. channelFound = true;
  351. break;
  352. case 1: // mute
  353. channelFound = true;
  354. break;
  355. case 2: // disabled
  356. // nothing
  357. break;
  358. default: // uhhhh.... freak out
  359. return false;
  360. }
  361. }
  362. if(!channelFound)
  363. {
  364. return false;
  365. }
  366. return true;
  367. }
  368. static uint64 GetHeaderMinimumAdditionalSize(const IMFFileHeader &fileHeader)
  369. {
  370. return 256 + fileHeader.patNum * 4 + fileHeader.insNum * sizeof(IMFInstrument);
  371. }
  372. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize)
  373. {
  374. IMFFileHeader fileHeader;
  375. if(!file.ReadStruct(fileHeader))
  376. {
  377. return ProbeWantMoreData;
  378. }
  379. if(!ValidateHeader(fileHeader))
  380. {
  381. return ProbeFailure;
  382. }
  383. return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
  384. }
  385. bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
  386. {
  387. IMFFileHeader fileHeader;
  388. file.Rewind();
  389. if(!file.ReadStruct(fileHeader))
  390. {
  391. return false;
  392. }
  393. if(!ValidateHeader(fileHeader))
  394. {
  395. return false;
  396. }
  397. if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
  398. {
  399. return false;
  400. }
  401. if(loadFlags == onlyVerifyHeader)
  402. {
  403. return true;
  404. }
  405. // Read channel configuration
  406. std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled
  407. uint8 detectedChannels = 0;
  408. for(uint8 chn = 0; chn < 32; chn++)
  409. {
  410. ChnSettings[chn].Reset();
  411. ChnSettings[chn].nPan = fileHeader.channels[chn].panning * 256 / 255;
  412. ChnSettings[chn].szName = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.channels[chn].name);
  413. // TODO: reverb/chorus?
  414. switch(fileHeader.channels[chn].status)
  415. {
  416. case 0: // enabled; don't worry about it
  417. detectedChannels = chn + 1;
  418. break;
  419. case 1: // mute
  420. ChnSettings[chn].dwFlags = CHN_MUTE;
  421. detectedChannels = chn + 1;
  422. break;
  423. case 2: // disabled
  424. ChnSettings[chn].dwFlags = CHN_MUTE;
  425. ignoreChannels[chn] = true;
  426. break;
  427. default: // uhhhh.... freak out
  428. return false;
  429. }
  430. }
  431. InitializeGlobals(MOD_TYPE_IMF);
  432. m_nChannels = detectedChannels;
  433. m_modFormat.formatName = U_("Imago Orpheus");
  434. m_modFormat.type = U_("imf");
  435. m_modFormat.charset = mpt::Charset::CP437;
  436. //From mikmod: work around an Orpheus bug
  437. if(fileHeader.channels[0].status == 0)
  438. {
  439. CHANNELINDEX chn;
  440. for(chn = 1; chn < 16; chn++)
  441. if(fileHeader.channels[chn].status != 1)
  442. break;
  443. if(chn == 16)
  444. for(chn = 1; chn < 16; chn++)
  445. ChnSettings[chn].dwFlags.reset(CHN_MUTE);
  446. }
  447. // Song Name
  448. m_songName = mpt::String::ReadBuf(mpt::String::nullTerminated, fileHeader.title);
  449. m_SongFlags.set(SONG_LINEARSLIDES, fileHeader.flags & IMFFileHeader::linearSlides);
  450. m_nDefaultSpeed = fileHeader.tempo;
  451. m_nDefaultTempo.Set(fileHeader.bpm);
  452. m_nDefaultGlobalVolume = fileHeader.master * 4u;
  453. m_nSamplePreAmp = fileHeader.amp;
  454. m_nInstruments = fileHeader.insNum;
  455. m_nSamples = 0; // Will be incremented later
  456. uint8 orders[256];
  457. file.ReadArray(orders);
  458. ReadOrderFromArray(Order(), orders, fileHeader.ordNum, uint16_max, 0xFF);
  459. // Read patterns
  460. if(loadFlags & loadPatternData)
  461. Patterns.ResizeArray(fileHeader.patNum);
  462. for(PATTERNINDEX pat = 0; pat < fileHeader.patNum; pat++)
  463. {
  464. const uint16 length = file.ReadUint16LE(), numRows = file.ReadUint16LE();
  465. FileReader patternChunk = file.ReadChunk(length - 4);
  466. if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, numRows))
  467. {
  468. continue;
  469. }
  470. ModCommand dummy;
  471. ROWINDEX row = 0;
  472. while(row < numRows)
  473. {
  474. uint8 mask = patternChunk.ReadUint8();
  475. if(mask == 0)
  476. {
  477. row++;
  478. continue;
  479. }
  480. uint8 channel = mask & 0x1F;
  481. ModCommand &m = (channel < GetNumChannels()) ? *Patterns[pat].GetpModCommand(row, channel) : dummy;
  482. if(mask & 0x20)
  483. {
  484. // Read note/instrument
  485. const auto [note, instr] = patternChunk.ReadArray<uint8, 2>();
  486. m.note = note;
  487. m.instr = instr;
  488. if(m.note == 160)
  489. {
  490. m.note = NOTE_KEYOFF;
  491. } else if(m.note == 255)
  492. {
  493. m.note = NOTE_NONE;
  494. } else
  495. {
  496. m.note = (m.note >> 4) * 12 + (m.note & 0x0F) + 12 + 1;
  497. if(!m.IsNoteOrEmpty())
  498. {
  499. m.note = NOTE_NONE;
  500. }
  501. }
  502. }
  503. if((mask & 0xC0) == 0xC0)
  504. {
  505. // Read both effects and figure out what to do with them
  506. const auto [e1c, e1d, e2c, e2d] = patternChunk.ReadArray<uint8, 4>(); // Command 1, Data 1, Command 2, Data 2
  507. if(e1c == 0x0C)
  508. {
  509. m.vol = std::min(e1d, uint8(0x40));
  510. m.volcmd = VOLCMD_VOLUME;
  511. m.command = e2c;
  512. m.param = e2d;
  513. } else if(e2c == 0x0C)
  514. {
  515. m.vol = std::min(e2d, uint8(0x40));
  516. m.volcmd = VOLCMD_VOLUME;
  517. m.command = e1c;
  518. m.param = e1d;
  519. } else if(e1c == 0x0A)
  520. {
  521. m.vol = e1d * 64 / 255;
  522. m.volcmd = VOLCMD_PANNING;
  523. m.command = e2c;
  524. m.param = e2d;
  525. } else if(e2c == 0x0A)
  526. {
  527. m.vol = e2d * 64 / 255;
  528. m.volcmd = VOLCMD_PANNING;
  529. m.command = e1c;
  530. m.param = e1d;
  531. } else
  532. {
  533. /* check if one of the effects is a 'global' effect
  534. -- if so, put it in some unused channel instead.
  535. otherwise pick the most important effect. */
  536. m.command = e2c;
  537. m.param = e2d;
  538. }
  539. } else if(mask & 0xC0)
  540. {
  541. // There's one effect, just stick it in the effect column
  542. const auto [command, param] = patternChunk.ReadArray<uint8, 2>();
  543. m.command = command;
  544. m.param = param;
  545. }
  546. if(m.command)
  547. ImportIMFEffect(m);
  548. if(ignoreChannels[channel] && m.IsGlobalCommand())
  549. m.command = CMD_NONE;
  550. }
  551. }
  552. SAMPLEINDEX firstSample = 1; // first sample index of the current instrument
  553. // read instruments
  554. for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++)
  555. {
  556. ModInstrument *instr = AllocateInstrument(ins + 1);
  557. IMFInstrument instrumentHeader;
  558. if(!file.ReadStruct(instrumentHeader) || instr == nullptr)
  559. {
  560. continue;
  561. }
  562. // Orpheus does not check this!
  563. //if(memcmp(instrumentHeader.ii10, "II10", 4) != 0)
  564. // return false;
  565. instrumentHeader.ConvertToMPT(*instr, firstSample);
  566. // Read this instrument's samples
  567. for(SAMPLEINDEX smp = 0; smp < instrumentHeader.smpNum; smp++)
  568. {
  569. IMFSample sampleHeader;
  570. file.ReadStruct(sampleHeader);
  571. const SAMPLEINDEX smpID = firstSample + smp;
  572. if(memcmp(sampleHeader.is10, "IS10", 4) || smpID >= MAX_SAMPLES)
  573. {
  574. continue;
  575. }
  576. m_nSamples = smpID;
  577. ModSample &sample = Samples[smpID];
  578. sampleHeader.ConvertToMPT(sample);
  579. m_szNames[smpID] = sample.filename;
  580. if(sampleHeader.length)
  581. {
  582. FileReader sampleChunk = file.ReadChunk(sampleHeader.length);
  583. if(loadFlags & loadSampleData)
  584. {
  585. SampleIO(
  586. sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit,
  587. SampleIO::mono,
  588. SampleIO::littleEndian,
  589. SampleIO::signedPCM)
  590. .ReadSample(sample, sampleChunk);
  591. }
  592. }
  593. }
  594. firstSample += instrumentHeader.smpNum;
  595. }
  596. return true;
  597. }
  598. OPENMPT_NAMESPACE_END