Load_med.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443
  1. /*
  2. * Load_med.cpp
  3. * ------------
  4. * Purpose: OctaMED / MED Soundstudio module loader
  5. * Notes : Support for synthesized instruments is still missing.
  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. #ifdef MPT_WITH_VST
  12. #include "../mptrack/Vstplug.h"
  13. #include "plugins/PluginManager.h"
  14. #endif // MPT_WITH_VST
  15. #include "mpt/io/base.hpp"
  16. #include "mpt/io/io.hpp"
  17. #include "mpt/io/io_span.hpp"
  18. #include "mpt/io/io_stdstream.hpp"
  19. #include <map>
  20. OPENMPT_NAMESPACE_BEGIN
  21. struct MMD0FileHeader
  22. {
  23. char mmd[3]; // "MMD" for the first song in file, "MCN" for the rest
  24. uint8be version; // '0'-'3'
  25. uint32be modLength; // Size of file
  26. uint32be songOffset; // Position in file for the first song
  27. uint16be playerSettings1[2]; // Internal variables for the play routine
  28. uint32be blockArrOffset; // Position in file for blocks (patterns)
  29. uint8be flags;
  30. uint8be reserved1[3];
  31. uint32be sampleArrOffset; // Position in file for samples (should be identical between songs)
  32. uint32be reserved2;
  33. uint32be expDataOffset; // Absolute offset in file for ExpData (0 if not present)
  34. uint32be reserved3;
  35. char playerSettings2[11]; // Internal variables for the play routine
  36. uint8be extraSongs; // Number of songs - 1
  37. };
  38. MPT_BINARY_STRUCT(MMD0FileHeader, 52)
  39. struct MMD0Sample
  40. {
  41. uint16be loopStart;
  42. uint16be loopLength;
  43. uint8be midiChannel;
  44. uint8be midiPreset;
  45. uint8be sampleVolume;
  46. int8be sampleTranspose;
  47. };
  48. MPT_BINARY_STRUCT(MMD0Sample, 8)
  49. // Song header for MMD0/MMD1
  50. struct MMD0Song
  51. {
  52. uint8be sequence[256];
  53. };
  54. MPT_BINARY_STRUCT(MMD0Song, 256)
  55. // Song header for MMD2/MMD3
  56. struct MMD2Song
  57. {
  58. enum Flags3
  59. {
  60. FLAG3_STEREO = 0x01, // Mixing in stereo
  61. FLAG3_FREEPAN = 0x02, // Mixing flag: free pan
  62. };
  63. uint32be playSeqTableOffset;
  64. uint32be sectionTableOffset;
  65. uint32be trackVolsOffset;
  66. uint16be numTracks;
  67. uint16be numPlaySeqs;
  68. uint32be trackPanOffset; // 0: all centered (according to docs, MED Soundstudio uses Amiga hard-panning instead)
  69. uint32be flags3;
  70. uint16be volAdjust; // Volume adjust (%)
  71. uint16be mixChannels; // Mixing channels, 0 means 4
  72. uint8be mixEchoType; // 0 = nothing, 1 = normal, 2 = cross
  73. uint8be mixEchoDepth; // 1 - 6, 0 = default
  74. uint16be mixEchoLength; // Echo length in milliseconds
  75. int8be mixStereoSep; // Stereo separation
  76. char pad0[223];
  77. };
  78. MPT_BINARY_STRUCT(MMD2Song, 256)
  79. // Common song header
  80. struct MMDSong
  81. {
  82. enum Flags
  83. {
  84. FLAG_FILTERON = 0x01, // The hardware audio filter is on
  85. FLAG_JUMPINGON = 0x02, // Mouse pointer jumping on
  86. FLAG_JUMP8TH = 0x04, // ump every 8th line (not in OctaMED Pro)
  87. FLAG_INSTRSATT = 0x08, // sng+samples indicator (not useful in MMDs)
  88. FLAG_VOLHEX = 0x10, // volumes are HEX
  89. FLAG_STSLIDE = 0x20, // use ST/NT/PT compatible sliding
  90. FLAG_8CHANNEL = 0x40, // this is OctaMED 5-8 channel song
  91. FLAG_SLOWHQ = 0x80, // HQ V2-4 compatibility mode
  92. };
  93. enum Flags2
  94. {
  95. FLAG2_BMASK = 0x1F, // (bits 0-4) BPM beat length (in lines)
  96. FLAG2_BPM = 0x20, // BPM mode on
  97. FLAG2_MIX = 0x80, // Module uses mixing
  98. };
  99. uint16be numBlocks; // Number of blocks in current song
  100. uint16be songLength; // MMD0: Number of sequence numbers in the play sequence list, MMD2: Number of sections
  101. char song[256];
  102. MMD0Song GetMMD0Song() const
  103. {
  104. static_assert(sizeof(MMD0Song) == sizeof(song));
  105. return mpt::bit_cast<MMD0Song>(song);
  106. }
  107. MMD2Song GetMMD2Song() const
  108. {
  109. static_assert(sizeof(MMD2Song) == sizeof(song));
  110. return mpt::bit_cast<MMD2Song>(song);
  111. }
  112. uint16be defaultTempo;
  113. int8be playTranspose; // The global play transpose value for current song
  114. uint8be flags;
  115. uint8be flags2;
  116. uint8be tempo2; // Timing pulses per line (ticks)
  117. uint8be trackVol[16]; // 1...64 in MMD0/MMD1, reserved in MMD2
  118. uint8be masterVol; // 1...64
  119. uint8be numSamples;
  120. };
  121. MPT_BINARY_STRUCT(MMDSong, 284)
  122. struct MMD2PlaySeq
  123. {
  124. char name[32];
  125. uint32be commandTableOffset;
  126. uint32be reserved;
  127. uint16be length; // Number of entries
  128. };
  129. MPT_BINARY_STRUCT(MMD2PlaySeq, 42)
  130. struct MMD0PatternHeader
  131. {
  132. uint8be numTracks;
  133. uint8be numRows;
  134. };
  135. MPT_BINARY_STRUCT(MMD0PatternHeader, 2)
  136. struct MMD1PatternHeader
  137. {
  138. uint16be numTracks;
  139. uint16be numRows;
  140. uint32be blockInfoOffset;
  141. };
  142. MPT_BINARY_STRUCT(MMD1PatternHeader, 8)
  143. struct MMDPlaySeqCommand
  144. {
  145. enum Command
  146. {
  147. kStop = 1,
  148. kJump = 2,
  149. };
  150. uint16be offset; // Offset within current play sequence, 0xFFFF = end of list
  151. uint8be command; // Stop = 1, Jump = 2
  152. uint8be extraSize;
  153. };
  154. MPT_BINARY_STRUCT(MMDPlaySeqCommand, 4)
  155. struct MMDBlockInfo
  156. {
  157. uint32be highlightMaskOffset;
  158. uint32be nameOffset;
  159. uint32be nameLength;
  160. uint32be pageTableOffset; // File offset of command page table
  161. uint32be cmdExtTableOffset; // File offset of command extension table (second parameter)
  162. uint32be reserved[4];
  163. };
  164. MPT_BINARY_STRUCT(MMDBlockInfo, 36)
  165. struct MMDInstrHeader
  166. {
  167. enum Types
  168. {
  169. VSTI = -4,
  170. HIGHLIFE = -3,
  171. HYBRID = -2,
  172. SYNTHETIC = -1,
  173. SAMPLE = 0, // an ordinary 1-octave sample (or MIDI)
  174. IFF5OCT = 1, // 5 octaves
  175. IFF3OCT = 2, // 3 octaves
  176. // The following ones are recognized by OctaMED Pro only
  177. IFF2OCT = 3, // 2 octaves
  178. IFF4OCT = 4, // 4 octaves
  179. IFF6OCT = 5, // 6 octaves
  180. IFF7OCT = 6, // 7 octaves
  181. // OctaMED Pro V5 + later
  182. EXTSAMPLE = 7, // two extra-low octaves
  183. TYPEMASK = 0x0F,
  184. S_16 = 0x10,
  185. STEREO = 0x20,
  186. DELTA = 0x40,
  187. PACKED = 0x80, // MMDPackedSampleHeader follows
  188. OBSOLETE_MD16 = 0x18,
  189. };
  190. uint32be length;
  191. int16be type;
  192. };
  193. MPT_BINARY_STRUCT(MMDInstrHeader, 6)
  194. struct MMDPackedSampleHeader
  195. {
  196. uint16be packType; // Only 1 = ADPCM is supported
  197. uint16be subType; // Packing subtype
  198. // ADPCM subtype
  199. // 1: g723_40
  200. // 2: g721
  201. // 3: g723_24
  202. uint8be commonFlags; // flags common to all packtypes (none defined so far)
  203. uint8be packerFlags; // flags for the specific packtype
  204. uint32be leftChLen; // packed length of left channel in bytes
  205. uint32be rightChLen; // packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES)
  206. };
  207. MPT_BINARY_STRUCT(MMDPackedSampleHeader, 14)
  208. struct MMDInstrExt
  209. {
  210. enum
  211. {
  212. SSFLG_LOOP = 0x01, // Loop On / Off
  213. SSFLG_EXTPSET = 0x02, // Ext.Preset
  214. SSFLG_DISABLED = 0x04, // Disabled
  215. SSFLG_PINGPONG = 0x08, // Ping-pong looping
  216. };
  217. uint8be hold; // 0...127
  218. uint8be decay; // 0...127
  219. uint8be suppressMidiOff;
  220. int8be finetune;
  221. // Below fields saved by >= V5
  222. uint8be defaultPitch;
  223. uint8be instrFlags;
  224. uint16be longMidiPreset; // Legacy MIDI program mode that doesn't use banks but a combination of two program change commands
  225. // Below fields saved by >= V5.02
  226. uint8be outputDevice;
  227. uint8be reserved;
  228. // Below fields saved by >= V7
  229. uint32be loopStart;
  230. uint32be loopLength;
  231. // Not sure which version starts saving those but they are saved by MED Soundstudio for Windows
  232. uint8 volume; // 0...127
  233. uint8 outputPort; // Index into user-configurable device list (NOT WinAPI port index)
  234. uint16le midiBank;
  235. };
  236. MPT_BINARY_STRUCT(MMDInstrExt, 22)
  237. struct MMDInstrInfo
  238. {
  239. char name[40];
  240. };
  241. MPT_BINARY_STRUCT(MMDInstrInfo, 40)
  242. struct MMD0Exp
  243. {
  244. uint32be nextModOffset;
  245. uint32be instrExtOffset;
  246. uint16be instrExtEntries;
  247. uint16be instrExtEntrySize;
  248. uint32be annoText;
  249. uint32be annoLength;
  250. uint32be instrInfoOffset;
  251. uint16be instrInfoEntries;
  252. uint16be instrInfoEntrySize;
  253. uint32be jumpMask;
  254. uint32be rgbTable;
  255. uint8be channelSplit[4];
  256. uint32be notationInfoOffset;
  257. uint32be songNameOffset;
  258. uint32be songNameLength;
  259. uint32be midiDumpOffset;
  260. uint32be mmdInfoOffset;
  261. uint32be arexxOffset;
  262. uint32be midiCmd3xOffset;
  263. uint32be trackInfoOffset; // Pointer to song->numtracks pointers to tag lists
  264. uint32be effectInfoOffset; // Pointers to group pointers
  265. uint32be tagEnd;
  266. };
  267. MPT_BINARY_STRUCT(MMD0Exp, 80)
  268. struct MMDTag
  269. {
  270. enum TagType
  271. {
  272. // Generic MMD tags
  273. MMDTAG_END = 0x00000000,
  274. MMDTAG_PTR = 0x80000000, // Data needs relocation
  275. MMDTAG_MUSTKNOW = 0x40000000, // Loader must fail if this isn't recognized
  276. MMDTAG_MUSTWARN = 0x20000000, // Loader must warn if this isn't recognized
  277. MMDTAG_MASK = 0x1FFFFFFF,
  278. // ExpData tags
  279. // # of effect groups, including the global group (will override settings in MMDSong struct), default = 1
  280. MMDTAG_EXP_NUMFXGROUPS = 1,
  281. MMDTAG_TRK_FXGROUP = 3,
  282. MMDTAG_TRK_NAME = 1, // trackinfo tags
  283. MMDTAG_TRK_NAMELEN = 2, // namelen includes zero term.
  284. // effectinfo tags
  285. MMDTAG_FX_ECHOTYPE = 1,
  286. MMDTAG_FX_ECHOLEN = 2,
  287. MMDTAG_FX_ECHODEPTH = 3,
  288. MMDTAG_FX_STEREOSEP = 4,
  289. MMDTAG_FX_GROUPNAME = 5, // the Global Effects group shouldn't have name saved!
  290. MMDTAG_FX_GRPNAMELEN = 6, // namelen includes zero term.
  291. };
  292. uint32be type;
  293. uint32be data;
  294. };
  295. MPT_BINARY_STRUCT(MMDTag, 8)
  296. struct MMDDump
  297. {
  298. uint32be length;
  299. uint32be dataPointer;
  300. uint16be extLength; // If >= 20: name follows as char[20]
  301. };
  302. MPT_BINARY_STRUCT(MMDDump, 10)
  303. static TEMPO MMDTempoToBPM(uint32 tempo, bool is8Ch, bool bpmMode, uint8 rowsPerBeat)
  304. {
  305. if(bpmMode && !is8Ch)
  306. {
  307. // You would have thought that we could use modern tempo mode here.
  308. // Alas, the number of ticks per row still influences the tempo. :(
  309. return TEMPO((tempo * rowsPerBeat) / 4.0);
  310. }
  311. if(is8Ch && tempo > 0)
  312. {
  313. LimitMax(tempo, 10u);
  314. // MED Soundstudio uses these tempos when importing old files
  315. static constexpr uint8 tempos[10] = {179, 164, 152, 141, 131, 123, 116, 110, 104, 99};
  316. return TEMPO(tempos[tempo - 1], 0);
  317. } else if(tempo > 0 && tempo <= 10)
  318. {
  319. // SoundTracker compatible tempo
  320. return TEMPO((6.0 * 1773447.0 / 14500.0) / tempo);
  321. }
  322. return TEMPO(tempo / 0.264);
  323. }
  324. static void ConvertMEDEffect(ModCommand &m, bool is8ch, bool bpmMode, uint8 rowsPerBeat, bool volHex)
  325. {
  326. switch(m.command)
  327. {
  328. case 0x04: // Vibrato (twice as deep as in ProTracker)
  329. m.command = CMD_VIBRATO;
  330. m.param = (std::min<uint8>(m.param >> 3, 0x0F) << 4) | std::min<uint8>((m.param & 0x0F) * 2, 0x0F);
  331. break;
  332. case 0x08: // Hold and decay
  333. m.command = CMD_NONE;
  334. break;
  335. case 0x09: // Set secondary speed
  336. if(m.param > 0 && m.param <= 20)
  337. m.command = CMD_SPEED;
  338. else
  339. m.command = CMD_NONE;
  340. break;
  341. case 0x0C: // Set Volume
  342. m.command = CMD_VOLUME;
  343. if(!volHex && m.param < 0x99)
  344. m.param = (m.param >> 4) * 10 + (m.param & 0x0F);
  345. else if(volHex)
  346. m.param = ((m.param & 0x7F) + 1) / 2;
  347. else
  348. m.command = CMD_NONE;
  349. break;
  350. case 0x0D:
  351. m.command = CMD_VOLUMESLIDE;
  352. break;
  353. case 0x0E: // Synth jump
  354. m.command = CMD_NONE;
  355. break;
  356. case 0x0F: // Misc
  357. if(m.param == 0)
  358. {
  359. m.command = CMD_PATTERNBREAK;
  360. } else if(m.param <= 0xF0)
  361. {
  362. m.command = CMD_TEMPO;
  363. if(m.param < 0x03) // This appears to be a bug in OctaMED which is not emulated in MED Soundstudio on Windows.
  364. m.param = 0x70;
  365. else
  366. m.param = mpt::saturate_round<ModCommand::PARAM>(MMDTempoToBPM(m.param, is8ch, bpmMode, rowsPerBeat).ToDouble());
  367. #ifdef MODPLUG_TRACKER
  368. if(m.param < 0x20)
  369. m.param = 0x20;
  370. #endif // MODPLUG_TRACKER
  371. } else switch(m.command)
  372. {
  373. case 0xF1: // Play note twice
  374. m.command = CMD_MODCMDEX;
  375. m.param = 0x93;
  376. break;
  377. case 0xF2: // Delay note
  378. m.command = CMD_MODCMDEX;
  379. m.param = 0xD3;
  380. break;
  381. case 0xF3: // Play note three times
  382. m.command = CMD_MODCMDEX;
  383. m.param = 0x92;
  384. break;
  385. case 0xF8: // Turn filter off
  386. case 0xF9: // Turn filter on
  387. m.command = CMD_MODCMDEX;
  388. m.param = 0xF9 - m.param;
  389. break;
  390. case 0xFA: // MIDI pedal on
  391. case 0xFB: // MIDI pedal off
  392. case 0xFD: // Set pitch
  393. case 0xFE: // End of song
  394. m.command = CMD_NONE;
  395. break;
  396. case 0xFF: // Turn note off
  397. m.note = NOTE_NOTECUT;
  398. m.command = CMD_NONE;
  399. break;
  400. default:
  401. m.command = CMD_NONE;
  402. break;
  403. }
  404. break;
  405. case 0x10: // MIDI message
  406. m.command = CMD_MIDI;
  407. m.param |= 0x80;
  408. break;
  409. case 0x11: // Slide pitch up
  410. m.command = CMD_MODCMDEX;
  411. m.param = 0x10 | std::min<uint8>(m.param, 0x0F);
  412. break;
  413. case 0x12: // Slide pitch down
  414. m.command = CMD_MODCMDEX;
  415. m.param = 0x20 | std::min<uint8>(m.param, 0x0F);
  416. break;
  417. case 0x14: // Vibrato (ProTracker compatible depth, but faster)
  418. m.command = CMD_VIBRATO;
  419. m.param = (std::min<uint8>((m.param >> 4) + 1, 0x0F) << 4) | (m.param & 0x0F);
  420. break;
  421. case 0x15: // Set finetune
  422. m.command = CMD_MODCMDEX;
  423. m.param = 0x50 | (m.param & 0x0F);
  424. break;
  425. case 0x16: // Loop
  426. m.command = CMD_MODCMDEX;
  427. m.param = 0x60 | std::min<uint8>(m.param, 0x0F);
  428. break;
  429. case 0x18: // Stop note
  430. m.command = CMD_MODCMDEX;
  431. m.param = 0xC0 | std::min<uint8>(m.param, 0x0F);
  432. break;
  433. case 0x19: // Sample Offset
  434. m.command = CMD_OFFSET;
  435. break;
  436. case 0x1A: // Slide volume up once
  437. m.command = CMD_MODCMDEX;
  438. m.param = 0xA0 | std::min<uint8>(m.param, 0x0F);
  439. break;
  440. case 0x1B: // Slide volume down once
  441. m.command = CMD_MODCMDEX;
  442. m.param = 0xB0 | std::min<uint8>(m.param, 0x0F);
  443. break;
  444. case 0x1C: // MIDI program
  445. if(m.param > 0 && m.param <= 128)
  446. {
  447. m.command = CMD_MIDI;
  448. m.param--;
  449. } else
  450. {
  451. m.command = CMD_NONE;
  452. }
  453. break;
  454. case 0x1D: // Pattern break (in hex)
  455. m.command = CMD_PATTERNBREAK;
  456. break;
  457. case 0x1E: // Repeat row
  458. m.command = CMD_MODCMDEX;
  459. m.param = 0xE0 | std::min<uint8>(m.param, 0x0F);
  460. break;
  461. case 0x1F: // Note delay and retrigger
  462. {
  463. if(m.param & 0xF0)
  464. {
  465. m.command = CMD_MODCMDEX;
  466. m.param = 0xD0 | (m.param >> 4);
  467. } else if(m.param & 0x0F)
  468. {
  469. m.command = CMD_MODCMDEX;
  470. m.param = 0x90 | m.param;
  471. } else
  472. {
  473. m.command = CMD_NONE;
  474. }
  475. break;
  476. }
  477. case 0x20: // Reverse sample + skip samples
  478. if(m.param == 0 && m.vol == 0)
  479. {
  480. if(m.IsNote())
  481. {
  482. m.command = CMD_S3MCMDEX;
  483. m.param = 0x9F;
  484. }
  485. } else
  486. {
  487. // Skip given number of samples
  488. m.command = CMD_NONE;
  489. }
  490. break;
  491. case 0x29: // Relative sample offset
  492. if(m.vol > 0)
  493. {
  494. m.command = CMD_OFFSETPERCENTAGE;
  495. m.param = mpt::saturate_cast<ModCommand::PARAM>(Util::muldiv_unsigned(m.param, 0x100, m.vol));
  496. } else
  497. {
  498. m.command = CMD_NONE;
  499. }
  500. break;
  501. case 0x2E: // Set panning
  502. if(m.param <= 0x10 || m.param >= 0xF0)
  503. {
  504. m.command = CMD_PANNING8;
  505. m.param = mpt::saturate_cast<ModCommand::PARAM>(((m.param ^ 0x80) - 0x70) * 8);
  506. } else
  507. {
  508. m.command = CMD_NONE;
  509. }
  510. break;
  511. default:
  512. if(m.command < 0x10)
  513. CSoundFile::ConvertModCommand(m);
  514. else
  515. m.command = CMD_NONE;
  516. break;
  517. }
  518. }
  519. #ifdef MPT_WITH_VST
  520. static std::wstring ReadMEDStringUTF16BE(FileReader &file)
  521. {
  522. FileReader chunk = file.ReadChunk(file.ReadUint32BE());
  523. std::wstring s(chunk.GetLength() / 2u, L'\0');
  524. for(auto &c : s)
  525. {
  526. c = chunk.ReadUint16BE();
  527. }
  528. return s;
  529. }
  530. #endif // MPT_WITH_VST
  531. static void MEDReadNextSong(FileReader &file, MMD0FileHeader &fileHeader, MMD0Exp &expData, MMDSong &songHeader)
  532. {
  533. file.ReadStruct(fileHeader);
  534. file.Seek(fileHeader.songOffset + 63 * sizeof(MMD0Sample));
  535. file.ReadStruct(songHeader);
  536. if(fileHeader.expDataOffset && file.Seek(fileHeader.expDataOffset))
  537. file.ReadStruct(expData);
  538. else
  539. expData = {};
  540. }
  541. static std::pair<CHANNELINDEX, SEQUENCEINDEX> MEDScanNumChannels(FileReader &file, const uint8 version)
  542. {
  543. MMD0FileHeader fileHeader;
  544. MMD0Exp expData;
  545. MMDSong songHeader;
  546. file.Rewind();
  547. uint32 songOffset = 0;
  548. MEDReadNextSong(file, fileHeader, expData, songHeader);
  549. SEQUENCEINDEX numSongs = std::min(MAX_SEQUENCES, mpt::saturate_cast<SEQUENCEINDEX>(fileHeader.expDataOffset ? fileHeader.extraSongs + 1 : 1));
  550. CHANNELINDEX numChannels = 4;
  551. // Scan patterns for max number of channels
  552. for(SEQUENCEINDEX song = 0; song < numSongs; song++)
  553. {
  554. const PATTERNINDEX numPatterns = songHeader.numBlocks;
  555. if(songHeader.numSamples > 63 || numPatterns > 0x7FFF)
  556. return {};
  557. for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
  558. {
  559. if(!file.Seek(fileHeader.blockArrOffset + pat * 4u)
  560. || !file.Seek(file.ReadUint32BE()))
  561. {
  562. continue;
  563. }
  564. numChannels = std::max(numChannels, static_cast<CHANNELINDEX>(version < 1 ? file.ReadUint8() : file.ReadUint16BE()));
  565. }
  566. // If song offsets are going backwards, reject the file
  567. if(expData.nextModOffset <= songOffset || !file.Seek(expData.nextModOffset))
  568. {
  569. numSongs = song + 1;
  570. break;
  571. }
  572. songOffset = expData.nextModOffset;
  573. MEDReadNextSong(file, fileHeader, expData, songHeader);
  574. }
  575. return {numChannels, numSongs};
  576. }
  577. static bool ValidateHeader(const MMD0FileHeader &fileHeader)
  578. {
  579. if(std::memcmp(fileHeader.mmd, "MMD", 3)
  580. || fileHeader.version < '0' || fileHeader.version > '3'
  581. || fileHeader.songOffset < sizeof(MMD0FileHeader)
  582. || fileHeader.songOffset > uint32_max - 63 * sizeof(MMD0Sample) - sizeof(MMDSong)
  583. || fileHeader.blockArrOffset < sizeof(MMD0FileHeader)
  584. || (fileHeader.sampleArrOffset > 0 && fileHeader.sampleArrOffset < sizeof(MMD0FileHeader))
  585. || fileHeader.expDataOffset > uint32_max - sizeof(MMD0Exp))
  586. {
  587. return false;
  588. }
  589. return true;
  590. }
  591. static uint64 GetHeaderMinimumAdditionalSize(const MMD0FileHeader &fileHeader)
  592. {
  593. return std::max<uint64>({ fileHeader.songOffset + 63 * sizeof(MMD0Sample) + sizeof(MMDSong),
  594. fileHeader.blockArrOffset,
  595. fileHeader.sampleArrOffset ? fileHeader.sampleArrOffset : sizeof(MMD0FileHeader),
  596. fileHeader.expDataOffset + sizeof(MMD0Exp) }) - sizeof(MMD0FileHeader);
  597. }
  598. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize)
  599. {
  600. MMD0FileHeader fileHeader;
  601. if(!file.ReadStruct(fileHeader))
  602. return ProbeWantMoreData;
  603. if(!ValidateHeader(fileHeader))
  604. return ProbeFailure;
  605. return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
  606. }
  607. bool CSoundFile::ReadMED(FileReader &file, ModLoadingFlags loadFlags)
  608. {
  609. file.Rewind();
  610. MMD0FileHeader fileHeader;
  611. if(!file.ReadStruct(fileHeader))
  612. return false;
  613. if(!ValidateHeader(fileHeader))
  614. return false;
  615. if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
  616. return false;
  617. if(loadFlags == onlyVerifyHeader)
  618. return true;
  619. InitializeGlobals(MOD_TYPE_MED);
  620. InitializeChannels();
  621. const uint8 version = fileHeader.version - '0';
  622. file.Seek(fileHeader.songOffset);
  623. FileReader sampleHeaderChunk = file.ReadChunk(63 * sizeof(MMD0Sample));
  624. MMDSong songHeader;
  625. file.ReadStruct(songHeader);
  626. if(songHeader.numSamples > 63 || songHeader.numBlocks > 0x7FFF)
  627. return false;
  628. MMD0Exp expData{};
  629. if(fileHeader.expDataOffset && file.Seek(fileHeader.expDataOffset))
  630. {
  631. file.ReadStruct(expData);
  632. }
  633. const auto [numChannels, numSongs] = MEDScanNumChannels(file, version);
  634. if(numChannels < 1 || numChannels > MAX_BASECHANNELS)
  635. return false;
  636. m_nChannels = numChannels;
  637. // Start with the instruments, as those are shared between songs
  638. std::vector<uint32be> instrOffsets;
  639. if(fileHeader.sampleArrOffset)
  640. {
  641. file.Seek(fileHeader.sampleArrOffset);
  642. file.ReadVector(instrOffsets, songHeader.numSamples);
  643. } else if(songHeader.numSamples > 0)
  644. {
  645. return false;
  646. }
  647. m_nInstruments = m_nSamples = songHeader.numSamples;
  648. // In MMD0 / MMD1, octave wrapping is not done for synth instruments
  649. // - It's required e.g. for automatic terminated to.mmd0 and you got to let the music.mmd1
  650. // - starkelsesirap.mmd0 (synth instruments) on the other hand don't need it
  651. // In MMD2 / MMD3, the mix flag is used instead.
  652. const bool hardwareMixSamples = (version < 2) || (version >= 2 && !(songHeader.flags2 & MMDSong::FLAG2_MIX));
  653. bool needInstruments = false;
  654. bool anySynthInstrs = false;
  655. #ifdef MPT_WITH_VST
  656. PLUGINDEX numPlugins = 0;
  657. #endif // MPT_WITH_VST
  658. for(SAMPLEINDEX ins = 1, smp = 1; ins <= m_nInstruments; ins++)
  659. {
  660. if(!AllocateInstrument(ins, smp))
  661. return false;
  662. ModInstrument &instr = *Instruments[ins];
  663. MMDInstrHeader instrHeader{};
  664. FileReader sampleChunk;
  665. if(instrOffsets[ins - 1] != 0 && file.Seek(instrOffsets[ins - 1]))
  666. {
  667. file.ReadStruct(instrHeader);
  668. uint32 chunkLength = instrHeader.length;
  669. if(instrHeader.type > 0 && (instrHeader.type & MMDInstrHeader::STEREO))
  670. chunkLength *= 2u;
  671. sampleChunk = file.ReadChunk(chunkLength);
  672. }
  673. const bool isSynth = instrHeader.type < 0;
  674. const size_t maskedType = static_cast<size_t>(instrHeader.type & MMDInstrHeader::TYPEMASK);
  675. #ifdef MPT_WITH_VST
  676. if(instrHeader.type == MMDInstrHeader::VSTI)
  677. {
  678. needInstruments = true;
  679. sampleChunk.Skip(6); // 00 00 <size of following data>
  680. const std::wstring type = ReadMEDStringUTF16BE(sampleChunk);
  681. const std::wstring name = ReadMEDStringUTF16BE(sampleChunk);
  682. if(type == L"VST")
  683. {
  684. auto &mixPlug = m_MixPlugins[numPlugins];
  685. mixPlug = {};
  686. mixPlug.Info.dwPluginId1 = Vst::kEffectMagic;
  687. mixPlug.Info.gain = 10;
  688. mixPlug.Info.szName = mpt::ToCharset(mpt::Charset::Locale, name);
  689. mixPlug.Info.szLibraryName = mpt::ToCharset(mpt::Charset::UTF8, name);
  690. instr.nMixPlug = numPlugins + 1;
  691. instr.nMidiChannel = MidiFirstChannel;
  692. instr.Transpose(-24);
  693. instr.AssignSample(0);
  694. // TODO: Figure out patch and routing data
  695. numPlugins++;
  696. }
  697. } else
  698. #endif // MPT_WITH_VST
  699. if(isSynth)
  700. {
  701. // TODO: Figure out synth instruments
  702. anySynthInstrs = true;
  703. instr.AssignSample(0);
  704. }
  705. uint8 numSamples = 1;
  706. static constexpr uint8 SamplesPerType[] = {1, 5, 3, 2, 4, 6, 7};
  707. if(!isSynth && maskedType < std::size(SamplesPerType))
  708. numSamples = SamplesPerType[maskedType];
  709. if(numSamples > 1)
  710. {
  711. static_assert(MAX_SAMPLES > 63 * 9, "Check IFFOCT multisample code");
  712. m_nSamples += numSamples - 1;
  713. needInstruments = true;
  714. static constexpr uint8 OctSampleMap[][8] =
  715. {
  716. {1, 1, 0, 0, 0, 0, 0, 0}, // 2
  717. {2, 2, 1, 1, 0, 0, 0, 0}, // 3
  718. {3, 3, 2, 2, 1, 0, 0, 0}, // 4
  719. {4, 3, 2, 1, 1, 0, 0, 0}, // 5
  720. {5, 4, 3, 2, 1, 0, 0, 0}, // 6
  721. {6, 5, 4, 3, 2, 1, 0, 0}, // 7
  722. };
  723. static constexpr int8 OctTransposeMap[][8] =
  724. {
  725. { 0, 0, -12, -12, -24, -36, -48, -60}, // 2
  726. { 0, 0, -12, -12, -24, -36, -48, -60}, // 3
  727. { 0, 0, -12, -12, -24, -36, -48, -60}, // 4
  728. {12, 0, -12, -24, -24, -36, -48, -60}, // 5
  729. {12, 0, -12, -24, -36, -48, -48, -60}, // 6
  730. {12, 0, -12, -24, -36, -48, -60, -72}, // 7
  731. };
  732. // TODO: Move octaves so that they align better (C-4 = lowest, we don't have access to the highest four octaves)
  733. for(int octave = 4; octave < 10; octave++)
  734. {
  735. for(int note = 0; note < 12; note++)
  736. {
  737. instr.Keyboard[12 * octave + note] = smp + OctSampleMap[numSamples - 2][octave - 4];
  738. instr.NoteMap[12 * octave + note] += OctTransposeMap[numSamples - 2][octave - 4];
  739. }
  740. }
  741. } else if(maskedType == MMDInstrHeader::EXTSAMPLE)
  742. {
  743. needInstruments = true;
  744. instr.Transpose(-24);
  745. } else if(!isSynth && hardwareMixSamples)
  746. {
  747. for(int octave = 7; octave < 10; octave++)
  748. {
  749. for(int note = 0; note < 12; note++)
  750. {
  751. instr.NoteMap[12 * octave + note] -= static_cast<uint8>((octave - 6) * 12);
  752. }
  753. }
  754. }
  755. MMD0Sample sampleHeader;
  756. sampleHeaderChunk.ReadStruct(sampleHeader);
  757. // midiChannel = 0xFF == midi instrument but with invalid channel, midiChannel = 0x00 == sample-based instrument?
  758. if(sampleHeader.midiChannel > 0 && sampleHeader.midiChannel <= 16)
  759. {
  760. instr.nMidiChannel = sampleHeader.midiChannel - 1 + MidiFirstChannel;
  761. needInstruments = true;
  762. #ifdef MPT_WITH_VST
  763. if(!isSynth)
  764. {
  765. auto &mixPlug = m_MixPlugins[numPlugins];
  766. mixPlug = {};
  767. mixPlug.Info.dwPluginId1 = PLUGMAGIC('V', 's', 't', 'P');
  768. mixPlug.Info.dwPluginId2 = PLUGMAGIC('M', 'M', 'I', 'D');
  769. mixPlug.Info.gain = 10;
  770. mixPlug.Info.szName = "MIDI Input Output";
  771. mixPlug.Info.szLibraryName = "MIDI Input Output";
  772. instr.nMixPlug = numPlugins + 1;
  773. instr.Transpose(-24);
  774. numPlugins++;
  775. }
  776. #endif // MPT_WITH_VST
  777. }
  778. if(sampleHeader.midiPreset > 0 && sampleHeader.midiPreset <= 128)
  779. {
  780. instr.nMidiProgram = sampleHeader.midiPreset;
  781. }
  782. for(SAMPLEINDEX i = 0; i < numSamples; i++)
  783. {
  784. ModSample &mptSmp = Samples[smp + i];
  785. mptSmp.Initialize(MOD_TYPE_MED);
  786. mptSmp.nVolume = 4u * std::min<uint8>(sampleHeader.sampleVolume, 64u);
  787. mptSmp.RelativeTone = sampleHeader.sampleTranspose;
  788. }
  789. if(isSynth || !(loadFlags & loadSampleData))
  790. {
  791. smp += numSamples;
  792. continue;
  793. }
  794. SampleIO sampleIO(
  795. SampleIO::_8bit,
  796. SampleIO::mono,
  797. SampleIO::bigEndian,
  798. SampleIO::signedPCM);
  799. const bool hasLoop = sampleHeader.loopLength > 1;
  800. SmpLength loopStart = sampleHeader.loopStart * 2;
  801. SmpLength loopEnd = loopStart + sampleHeader.loopLength * 2;
  802. SmpLength length = mpt::saturate_cast<SmpLength>(sampleChunk.GetLength());
  803. if(instrHeader.type & MMDInstrHeader::S_16)
  804. {
  805. sampleIO |= SampleIO::_16bit;
  806. length /= 2;
  807. }
  808. if(instrHeader.type & MMDInstrHeader::STEREO)
  809. {
  810. sampleIO |= SampleIO::stereoSplit;
  811. length /= 2;
  812. }
  813. if(instrHeader.type & MMDInstrHeader::DELTA)
  814. {
  815. sampleIO |= SampleIO::deltaPCM;
  816. }
  817. if(numSamples > 1)
  818. length = length / ((1u << numSamples) - 1);
  819. for(SAMPLEINDEX i = 0; i < numSamples; i++)
  820. {
  821. ModSample &mptSmp = Samples[smp + i];
  822. mptSmp.nLength = length;
  823. sampleIO.ReadSample(mptSmp, sampleChunk);
  824. if(hasLoop)
  825. {
  826. mptSmp.nLoopStart = loopStart;
  827. mptSmp.nLoopEnd = loopEnd;
  828. mptSmp.uFlags.set(CHN_LOOP);
  829. }
  830. length *= 2;
  831. loopStart *= 2;
  832. loopEnd *= 2;
  833. }
  834. smp += numSamples;
  835. }
  836. if(expData.instrExtOffset != 0 && expData.instrExtEntries != 0 && file.Seek(expData.instrExtOffset))
  837. {
  838. const uint16 entries = std::min<uint16>(expData.instrExtEntries, songHeader.numSamples);
  839. const uint16 size = expData.instrExtEntrySize;
  840. for(uint16 i = 0; i < entries; i++)
  841. {
  842. MMDInstrExt instrExt;
  843. file.ReadStructPartial(instrExt, size);
  844. ModInstrument &ins = *Instruments[i + 1];
  845. if(instrExt.hold)
  846. {
  847. ins.VolEnv.assign({
  848. EnvelopeNode{0u, ENVELOPE_MAX},
  849. EnvelopeNode{static_cast<EnvelopeNode::tick_t>(instrExt.hold - 1), ENVELOPE_MAX},
  850. EnvelopeNode{static_cast<EnvelopeNode::tick_t>(instrExt.hold + (instrExt.decay ? 64u / instrExt.decay : 0u)), ENVELOPE_MIN},
  851. });
  852. if(instrExt.hold == 1)
  853. ins.VolEnv.erase(ins.VolEnv.begin());
  854. ins.nFadeOut = instrExt.decay ? (instrExt.decay * 512) : 32767;
  855. ins.VolEnv.dwFlags.set(ENV_ENABLED);
  856. needInstruments = true;
  857. }
  858. if(size > offsetof(MMDInstrExt, volume))
  859. ins.nGlobalVol = (instrExt.volume + 1u) / 2u;
  860. if(size > offsetof(MMDInstrExt, midiBank))
  861. ins.wMidiBank = instrExt.midiBank;
  862. #ifdef MPT_WITH_VST
  863. if(ins.nMixPlug > 0)
  864. {
  865. PLUGINDEX plug = ins.nMixPlug - 1;
  866. auto &mixPlug = m_MixPlugins[plug];
  867. if(mixPlug.Info.dwPluginId2 == PLUGMAGIC('M', 'M', 'I', 'D'))
  868. {
  869. float dev = (instrExt.outputDevice + 1) / 65536.0f; // Magic code from MidiInOut.h :(
  870. mixPlug.pluginData.resize(3 * sizeof(uint32));
  871. auto memFile = std::make_pair(mpt::as_span(mixPlug.pluginData), mpt::IO::Offset(0));
  872. mpt::IO::WriteIntLE<uint32>(memFile, 0); // Plugin data type
  873. mpt::IO::Write(memFile, IEEE754binary32LE{0}); // Input device
  874. mpt::IO::Write(memFile, IEEE754binary32LE{dev}); // Output device
  875. // Check if we already have another plugin referencing this output device
  876. for(PLUGINDEX p = 0; p < plug; p++)
  877. {
  878. const auto &otherPlug = m_MixPlugins[p];
  879. if(otherPlug.Info.dwPluginId1 == mixPlug.Info.dwPluginId1
  880. && otherPlug.Info.dwPluginId2 == mixPlug.Info.dwPluginId2
  881. && otherPlug.pluginData == mixPlug.pluginData)
  882. {
  883. ins.nMixPlug = p + 1;
  884. mixPlug = {};
  885. break;
  886. }
  887. }
  888. }
  889. }
  890. #endif // MPT_WITH_VST
  891. ModSample &sample = Samples[ins.Keyboard[NOTE_MIDDLEC]];
  892. sample.nFineTune = MOD2XMFineTune(instrExt.finetune);
  893. if(size > offsetof(MMDInstrExt, loopLength))
  894. {
  895. sample.nLoopStart = instrExt.loopStart;
  896. sample.nLoopEnd = instrExt.loopStart + instrExt.loopLength;
  897. }
  898. if(size > offsetof(MMDInstrExt, instrFlags))
  899. {
  900. sample.uFlags.set(CHN_LOOP, (instrExt.instrFlags & MMDInstrExt::SSFLG_LOOP) != 0);
  901. sample.uFlags.set(CHN_PINGPONGLOOP, (instrExt.instrFlags & MMDInstrExt::SSFLG_PINGPONG) != 0);
  902. if(instrExt.instrFlags & MMDInstrExt::SSFLG_DISABLED)
  903. sample.nGlobalVol = 0;
  904. }
  905. }
  906. }
  907. if(expData.instrInfoOffset != 0 && expData.instrInfoEntries != 0 && file.Seek(expData.instrInfoOffset))
  908. {
  909. const uint16 entries = std::min<uint16>(expData.instrInfoEntries, songHeader.numSamples);
  910. const uint16 size = expData.instrInfoEntrySize;
  911. for(uint16 i = 0; i < entries; i++)
  912. {
  913. MMDInstrInfo instrInfo;
  914. file.ReadStructPartial(instrInfo, size);
  915. Instruments[i + 1]->name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, instrInfo.name);
  916. for(auto smp : Instruments[i + 1]->GetSamples())
  917. {
  918. m_szNames[smp] = Instruments[i + 1]->name;
  919. }
  920. }
  921. }
  922. // Setup a program change macro for command 1C (even if MIDI plugin is disabled, as otherwise these commands may act as filter commands)
  923. m_MidiCfg.ClearZxxMacros();
  924. m_MidiCfg.SFx[0] = "Cc z";
  925. file.Rewind();
  926. PATTERNINDEX basePattern = 0;
  927. for(SEQUENCEINDEX song = 0; song < numSongs; song++)
  928. {
  929. MEDReadNextSong(file, fileHeader, expData, songHeader);
  930. if(song != 0)
  931. {
  932. if(Order.AddSequence() == SEQUENCEINDEX_INVALID)
  933. return false;
  934. }
  935. ModSequence &order = Order(song);
  936. std::map<ORDERINDEX, ORDERINDEX> jumpTargets;
  937. order.clear();
  938. uint32 preamp = 32;
  939. if(version < 2)
  940. {
  941. if(songHeader.songLength > 256 || m_nChannels > 16)
  942. return false;
  943. ReadOrderFromArray(order, songHeader.GetMMD0Song().sequence, songHeader.songLength);
  944. for(auto &ord : order)
  945. {
  946. ord += basePattern;
  947. }
  948. SetupMODPanning(true);
  949. for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
  950. {
  951. ChnSettings[chn].nVolume = std::min<uint8>(songHeader.trackVol[chn], 64);
  952. }
  953. } else
  954. {
  955. const MMD2Song header = songHeader.GetMMD2Song();
  956. if(header.numTracks < 1 || header.numTracks > 64 || m_nChannels > 64)
  957. return false;
  958. const bool freePan = (header.flags3 & MMD2Song::FLAG3_FREEPAN);
  959. if(header.volAdjust)
  960. preamp = Util::muldivr_unsigned(preamp, std::min<uint16>(header.volAdjust, 800), 100);
  961. if (freePan)
  962. preamp /= 2;
  963. if(file.Seek(header.trackVolsOffset))
  964. {
  965. for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
  966. {
  967. ChnSettings[chn].nVolume = std::min<uint8>(file.ReadUint8(), 64);
  968. }
  969. }
  970. if(header.trackPanOffset && file.Seek(header.trackPanOffset))
  971. {
  972. for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
  973. {
  974. ChnSettings[chn].nPan = (Clamp<int8, int8>(file.ReadInt8(), -16, 16) + 16) * 8;
  975. }
  976. } else
  977. {
  978. SetupMODPanning(true);
  979. }
  980. std::vector<uint16be> sections;
  981. if(!file.Seek(header.sectionTableOffset)
  982. || !file.CanRead(songHeader.songLength * 2)
  983. || !file.ReadVector(sections, songHeader.songLength))
  984. continue;
  985. for(uint16 section : sections)
  986. {
  987. if(section > header.numPlaySeqs)
  988. continue;
  989. file.Seek(header.playSeqTableOffset + section * 4);
  990. if(!file.Seek(file.ReadUint32BE()) || !file.CanRead(sizeof(MMD2PlaySeq)))
  991. continue;
  992. MMD2PlaySeq playSeq;
  993. file.ReadStruct(playSeq);
  994. if(!order.empty())
  995. order.push_back(order.GetIgnoreIndex());
  996. size_t readOrders = playSeq.length;
  997. if(!file.CanRead(readOrders))
  998. LimitMax(readOrders, file.BytesLeft());
  999. LimitMax(readOrders, ORDERINDEX_MAX);
  1000. size_t orderStart = order.size();
  1001. order.reserve(orderStart + readOrders);
  1002. for(size_t ord = 0; ord < readOrders; ord++)
  1003. {
  1004. PATTERNINDEX pat = file.ReadUint16BE();
  1005. if(pat < 0x8000)
  1006. {
  1007. order.push_back(basePattern + pat);
  1008. }
  1009. }
  1010. if(playSeq.name[0])
  1011. order.SetName(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, mpt::String::ReadAutoBuf(playSeq.name)));
  1012. // Play commands (jump / stop)
  1013. if(playSeq.commandTableOffset > 0 && file.Seek(playSeq.commandTableOffset))
  1014. {
  1015. MMDPlaySeqCommand command;
  1016. while(file.ReadStruct(command))
  1017. {
  1018. FileReader chunk = file.ReadChunk(command.extraSize);
  1019. ORDERINDEX ord = mpt::saturate_cast<ORDERINDEX>(orderStart + command.offset);
  1020. if(command.offset == 0xFFFF || ord >= order.size())
  1021. break;
  1022. if(command.command == MMDPlaySeqCommand::kStop)
  1023. {
  1024. order[ord] = order.GetInvalidPatIndex();
  1025. } else if(command.command == MMDPlaySeqCommand::kJump)
  1026. {
  1027. jumpTargets[ord] = chunk.ReadUint16BE();
  1028. order[ord] = order.GetIgnoreIndex();
  1029. }
  1030. }
  1031. }
  1032. }
  1033. }
  1034. const bool volHex = (songHeader.flags & MMDSong::FLAG_VOLHEX) != 0;
  1035. const bool is8Ch = (songHeader.flags & MMDSong::FLAG_8CHANNEL) != 0;
  1036. const bool bpmMode = (songHeader.flags2 & MMDSong::FLAG2_BPM) != 0;
  1037. const uint8 rowsPerBeat = 1 + (songHeader.flags2 & MMDSong::FLAG2_BMASK);
  1038. m_nDefaultTempo = MMDTempoToBPM(songHeader.defaultTempo, is8Ch, bpmMode, rowsPerBeat);
  1039. m_nDefaultSpeed = Clamp<uint8, uint8>(songHeader.tempo2, 1, 32);
  1040. if(bpmMode)
  1041. {
  1042. m_nDefaultRowsPerBeat = rowsPerBeat;
  1043. m_nDefaultRowsPerMeasure = m_nDefaultRowsPerBeat * 4u;
  1044. }
  1045. if(songHeader.masterVol)
  1046. m_nDefaultGlobalVolume = std::min<uint8>(songHeader.masterVol, 64) * 4;
  1047. m_nSamplePreAmp = m_nVSTiVolume = preamp;
  1048. // For MED, this affects both volume and pitch slides
  1049. m_SongFlags.set(SONG_FASTVOLSLIDES, !(songHeader.flags & MMDSong::FLAG_STSLIDE));
  1050. if(expData.songNameOffset && file.Seek(expData.songNameOffset))
  1051. {
  1052. file.ReadString<mpt::String::maybeNullTerminated>(m_songName, expData.songNameLength);
  1053. if(numSongs > 1)
  1054. order.SetName(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, m_songName));
  1055. }
  1056. if(expData.annoLength > 1 && file.Seek(expData.annoText))
  1057. {
  1058. m_songMessage.Read(file, expData.annoLength - 1, SongMessage::leAutodetect);
  1059. }
  1060. #ifdef MPT_WITH_VST
  1061. // Read MIDI messages
  1062. if(expData.midiDumpOffset && file.Seek(expData.midiDumpOffset) && file.CanRead(8))
  1063. {
  1064. uint16 numDumps = std::min(file.ReadUint16BE(), static_cast<uint16>(m_MidiCfg.Zxx.size()));
  1065. file.Skip(6);
  1066. if(file.CanRead(numDumps * 4))
  1067. {
  1068. std::vector<uint32be> dumpPointers;
  1069. file.ReadVector(dumpPointers, numDumps);
  1070. for(uint16 dump = 0; dump < numDumps; dump++)
  1071. {
  1072. if(!file.Seek(dumpPointers[dump]) || !file.CanRead(sizeof(MMDDump)))
  1073. continue;
  1074. MMDDump dumpHeader;
  1075. file.ReadStruct(dumpHeader);
  1076. if(!file.Seek(dumpHeader.dataPointer) || !file.CanRead(dumpHeader.length))
  1077. continue;
  1078. std::array<char, kMacroLength> macro{};
  1079. auto length = std::min(static_cast<size_t>(dumpHeader.length), macro.size() / 2u);
  1080. for(size_t i = 0; i < length; i++)
  1081. {
  1082. const uint8 byte = file.ReadUint8(), high = byte >> 4, low = byte & 0x0F;
  1083. macro[i * 2] = high + (high < 0x0A ? '0' : 'A' - 0x0A);
  1084. macro[i * 2 + 1] = low + (low < 0x0A ? '0' : 'A' - 0x0A);
  1085. }
  1086. m_MidiCfg.Zxx[dump] = std::string_view{macro.data(), length * 2};
  1087. }
  1088. }
  1089. }
  1090. #endif // MPT_WITH_VST
  1091. if(expData.mmdInfoOffset && file.Seek(expData.mmdInfoOffset) && file.CanRead(12))
  1092. {
  1093. file.Skip(6); // Next info file (unused) + reserved
  1094. if(file.ReadUint16BE() == 1) // ASCII text
  1095. {
  1096. uint32 length = file.ReadUint32BE();
  1097. if(length && file.CanRead(length))
  1098. {
  1099. const auto oldMsg = std::move(m_songMessage);
  1100. m_songMessage.Read(file, length, SongMessage::leAutodetect);
  1101. if(!oldMsg.empty())
  1102. m_songMessage.SetRaw(oldMsg + std::string(2, SongMessage::InternalLineEnding) + m_songMessage);
  1103. }
  1104. }
  1105. }
  1106. // Track Names
  1107. if(version >= 2 && expData.trackInfoOffset)
  1108. {
  1109. for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
  1110. {
  1111. if(file.Seek(expData.trackInfoOffset + chn * 4)
  1112. && file.Seek(file.ReadUint32BE()))
  1113. {
  1114. uint32 nameOffset = 0, nameLength = 0;
  1115. while(file.CanRead(sizeof(MMDTag)))
  1116. {
  1117. MMDTag tag;
  1118. file.ReadStruct(tag);
  1119. if(tag.type == MMDTag::MMDTAG_END)
  1120. break;
  1121. switch(tag.type & MMDTag::MMDTAG_MASK)
  1122. {
  1123. case MMDTag::MMDTAG_TRK_NAME: nameOffset = tag.data; break;
  1124. case MMDTag::MMDTAG_TRK_NAMELEN: nameLength = tag.data; break;
  1125. }
  1126. }
  1127. if(nameOffset > 0 && nameLength > 0 && file.Seek(nameOffset))
  1128. {
  1129. file.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[chn].szName, nameLength);
  1130. }
  1131. }
  1132. }
  1133. }
  1134. PATTERNINDEX numPatterns = songHeader.numBlocks;
  1135. Patterns.ResizeArray(basePattern + numPatterns);
  1136. for(PATTERNINDEX pat = 0; pat < numPatterns; pat++)
  1137. {
  1138. if(!(loadFlags & loadPatternData)
  1139. || !file.Seek(fileHeader.blockArrOffset + pat * 4u)
  1140. || !file.Seek(file.ReadUint32BE()))
  1141. {
  1142. continue;
  1143. }
  1144. CHANNELINDEX numTracks;
  1145. ROWINDEX numRows;
  1146. std::string patName;
  1147. int transpose;
  1148. FileReader cmdExt;
  1149. if(version < 1)
  1150. {
  1151. transpose = NOTE_MIN + 47;
  1152. MMD0PatternHeader patHeader;
  1153. file.ReadStruct(patHeader);
  1154. numTracks = patHeader.numTracks;
  1155. numRows = patHeader.numRows + 1;
  1156. } else
  1157. {
  1158. transpose = NOTE_MIN + (version <= 2 ? 47 : 23) + songHeader.playTranspose;
  1159. MMD1PatternHeader patHeader;
  1160. file.ReadStruct(patHeader);
  1161. numTracks = patHeader.numTracks;
  1162. numRows = patHeader.numRows + 1;
  1163. if(patHeader.blockInfoOffset)
  1164. {
  1165. auto offset = file.GetPosition();
  1166. file.Seek(patHeader.blockInfoOffset);
  1167. MMDBlockInfo blockInfo;
  1168. file.ReadStruct(blockInfo);
  1169. if(file.Seek(blockInfo.nameOffset))
  1170. {
  1171. // We have now chased four pointers to get this far... lovely format.
  1172. file.ReadString<mpt::String::maybeNullTerminated>(patName, blockInfo.nameLength);
  1173. }
  1174. if(blockInfo.cmdExtTableOffset
  1175. && file.Seek(blockInfo.cmdExtTableOffset)
  1176. && file.Seek(file.ReadUint32BE()))
  1177. {
  1178. cmdExt = file.ReadChunk(numTracks * numRows);
  1179. }
  1180. file.Seek(offset);
  1181. }
  1182. }
  1183. if(!Patterns.Insert(basePattern + pat, numRows))
  1184. continue;
  1185. CPattern &pattern = Patterns[basePattern + pat];
  1186. pattern.SetName(patName);
  1187. LimitMax(numTracks, m_nChannels);
  1188. for(ROWINDEX row = 0; row < numRows; row++)
  1189. {
  1190. ModCommand *m = pattern.GetpModCommand(row, 0);
  1191. for(CHANNELINDEX chn = 0; chn < numTracks; chn++, m++)
  1192. {
  1193. int note = NOTE_NONE;
  1194. if(version < 1)
  1195. {
  1196. const auto [noteInstr, instrCmd, param] = file.ReadArray<uint8, 3>();
  1197. if(noteInstr & 0x3F)
  1198. note = (noteInstr & 0x3F) + transpose;
  1199. m->instr = (instrCmd >> 4) | ((noteInstr & 0x80) >> 3) | ((noteInstr & 0x40) >> 1);
  1200. m->command = instrCmd & 0x0F;
  1201. m->param = param;
  1202. } else
  1203. {
  1204. const auto [noteVal, instr, command, param1] = file.ReadArray<uint8, 4>();
  1205. m->vol = cmdExt.ReadUint8();
  1206. if(noteVal & 0x7F)
  1207. note = (noteVal & 0x7F) + transpose;
  1208. else if(noteVal == 0x80)
  1209. m->note = NOTE_NOTECUT;
  1210. m->instr = instr & 0x3F;
  1211. m->command = command;
  1212. m->param = param1;
  1213. }
  1214. // Octave wrapping for 4-channel modules (TODO: this should not be set because of synth instruments)
  1215. if(hardwareMixSamples && note >= NOTE_MIDDLEC + 2 * 12)
  1216. needInstruments = true;
  1217. if(note >= NOTE_MIN && note <= NOTE_MAX)
  1218. m->note = static_cast<ModCommand::NOTE>(note);
  1219. ConvertMEDEffect(*m, is8Ch, bpmMode, rowsPerBeat, volHex);
  1220. }
  1221. }
  1222. }
  1223. // Fix jump order commands
  1224. for(const auto & [from, to] : jumpTargets)
  1225. {
  1226. PATTERNINDEX pat;
  1227. if(from > 0 && order.IsValidPat(from - 1))
  1228. {
  1229. pat = order.EnsureUnique(from - 1);
  1230. } else
  1231. {
  1232. if(to == from + 1) // No action required
  1233. continue;
  1234. pat = Patterns.InsertAny(1);
  1235. if(pat == PATTERNINDEX_INVALID)
  1236. continue;
  1237. order[from] = pat;
  1238. }
  1239. Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, mpt::saturate_cast<ModCommand::PARAM>(to)).Row(Patterns[pat].GetNumRows() - 1).RetryPreviousRow());
  1240. if(pat >= numPatterns)
  1241. numPatterns = pat + 1;
  1242. }
  1243. basePattern += numPatterns;
  1244. if(!expData.nextModOffset || !file.Seek(expData.nextModOffset))
  1245. break;
  1246. }
  1247. Order.SetSequence(0);
  1248. if(!needInstruments)
  1249. {
  1250. for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++)
  1251. {
  1252. delete Instruments[ins];
  1253. Instruments[ins] = nullptr;
  1254. }
  1255. m_nInstruments = 0;
  1256. }
  1257. if(anySynthInstrs)
  1258. AddToLog(LogWarning, U_("Synthesized MED instruments are not supported."));
  1259. const mpt::uchar *madeWithTracker = MPT_ULITERAL("");
  1260. switch(version)
  1261. {
  1262. case 0: madeWithTracker = m_nChannels > 4 ? MPT_ULITERAL("OctaMED v2.10 (MMD0)") : MPT_ULITERAL("MED v2 (MMD0)"); break;
  1263. case 1: madeWithTracker = MPT_ULITERAL("OctaMED v4 (MMD1)"); break;
  1264. case 2: madeWithTracker = MPT_ULITERAL("OctaMED v5 (MMD2)"); break;
  1265. case 3: madeWithTracker = MPT_ULITERAL("OctaMED Soundstudio (MMD3)"); break;
  1266. }
  1267. m_modFormat.formatName = MPT_UFORMAT("OctaMED (MMD{})")(version);
  1268. m_modFormat.type = MPT_USTRING("med");
  1269. m_modFormat.madeWithTracker = madeWithTracker;
  1270. m_modFormat.charset = mpt::Charset::Amiga_no_C1;
  1271. return true;
  1272. }
  1273. OPENMPT_NAMESPACE_END